]> git.saurik.com Git - apple/xnu.git/blame - bsd/kern/kern_symfile.c
xnu-1699.24.23.tar.gz
[apple/xnu.git] / bsd / kern / kern_symfile.c
CommitLineData
1c79356b 1/*
2d21ac55 2 * Copyright (c) 2000-2006 Apple Computer, Inc. All rights reserved.
5d5c5d0d 3 *
2d21ac55 4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
1c79356b 5 *
2d21ac55
A
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.
8f6c56a5 14 *
2d21ac55
A
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
8f6c56a5
A
20 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
21 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
2d21ac55
A
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.
8f6c56a5 25 *
2d21ac55 26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
1c79356b
A
27 */
28/* Copyright (c) 1998 Apple Computer, Inc. All rights reserved.
29 *
30 * File: bsd/kern/kern_symfile.c
31 *
1c79356b 32 * HISTORY
1c79356b
A
33 */
34
35#include <mach/vm_param.h>
36
37#include <sys/param.h>
38#include <sys/systm.h>
39#include <sys/signalvar.h>
40#include <sys/resourcevar.h>
41#include <sys/namei.h>
91447636
A
42#include <sys/vnode_internal.h>
43#include <sys/proc_internal.h>
44#include <sys/kauth.h>
1c79356b
A
45#include <sys/timeb.h>
46#include <sys/times.h>
1c79356b 47#include <sys/acct.h>
91447636 48#include <sys/file_internal.h>
1c79356b
A
49#include <sys/uio.h>
50#include <sys/kernel.h>
51#include <sys/stat.h>
91447636
A
52#include <sys/disk.h>
53#include <sys/conf.h>
1c79356b
A
54
55#include <mach-o/loader.h>
56#include <mach-o/nlist.h>
57
91447636 58#include <kern/kalloc.h>
1c79356b 59#include <vm/vm_kern.h>
91447636 60#include <pexpert/pexpert.h>
3a60a9f5 61#include <IOKit/IOHibernatePrivate.h>
1c79356b 62
2d21ac55
A
63/* This function is called from kern_sysctl in the current process context;
64 * it is exported with the System6.0.exports, but this appears to be a legacy
65 * export, as there are no internal consumers.
1c79356b 66 */
2d21ac55
A
67int
68get_kernel_symfile(__unused proc_t p, __unused char const **symfile)
1c79356b 69{
2d21ac55 70 return KERN_FAILURE;
0b4e3aa0 71}
91447636 72
3a60a9f5
A
73struct kern_direct_file_io_ref_t
74{
6d2010ae
A
75 vfs_context_t ctx;
76 struct vnode * vp;
77 dev_t device;
3a60a9f5
A
78};
79
80
6d2010ae 81static int file_ioctl(void * p1, void * p2, u_long theIoctl, caddr_t result)
3a60a9f5 82{
b0d623f7 83 dev_t device = *(dev_t*) p1;
3a60a9f5
A
84
85 return ((*bdevsw[major(device)].d_ioctl)
86 (device, theIoctl, result, S_IFBLK, p2));
87}
88
6d2010ae 89static int device_ioctl(void * p1, __unused void * p2, u_long theIoctl, caddr_t result)
3a60a9f5
A
90{
91 return (VNOP_IOCTL(p1, theIoctl, result, 0, p2));
92}
93
94struct kern_direct_file_io_ref_t *
95kern_open_file_for_direct_io(const char * name,
96 kern_get_file_extents_callback_t callback,
97 void * callback_ref,
6d2010ae
A
98 dev_t * partition_device_result,
99 dev_t * image_device_result,
3a60a9f5 100 uint64_t * partitionbase_result,
0b4c1975 101 uint64_t * maxiocount_result,
6d2010ae
A
102 uint32_t * oflags,
103 off_t offset,
104 caddr_t addr,
105 vm_size_t len)
3a60a9f5
A
106{
107 struct kern_direct_file_io_ref_t * ref;
108
2d21ac55 109 proc_t p;
3a60a9f5
A
110 struct vnode_attr va;
111 int error;
112 off_t f_offset;
6d2010ae
A
113 off_t filelength;
114 uint64_t fileblk;
115 size_t filechunk;
116 uint64_t physoffset;
3a60a9f5 117 dev_t device;
6d2010ae
A
118 dev_t target = 0;
119 int isssd = 0;
120 uint32_t flags = 0;
121 uint32_t blksize;
3a60a9f5 122 off_t maxiocount, count;
6d2010ae 123 boolean_t locked = FALSE;
3a60a9f5 124
6d2010ae
A
125 int (*do_ioctl)(void * p1, void * p2, u_long theIoctl, caddr_t result);
126 void * p1 = NULL;
127 void * p2 = NULL;
3a60a9f5
A
128
129 error = EFAULT;
130
131 ref = (struct kern_direct_file_io_ref_t *) kalloc(sizeof(struct kern_direct_file_io_ref_t));
132 if (!ref)
133 {
134 error = EFAULT;
135 goto out;
136 }
137
138 ref->vp = NULL;
6d2010ae 139 p = kernproc;
2d21ac55 140 ref->ctx = vfs_context_create(vfs_context_current());
3a60a9f5 141
2d21ac55 142 if ((error = vnode_open(name, (O_CREAT | FWRITE), (0), 0, &ref->vp, ref->ctx)))
3a60a9f5
A
143 goto out;
144
6d2010ae
A
145 if (addr && len)
146 {
147 if ((error = kern_write_file(ref, offset, addr, len)))
148 goto out;
149 }
150
3a60a9f5
A
151 VATTR_INIT(&va);
152 VATTR_WANTED(&va, va_rdev);
153 VATTR_WANTED(&va, va_fsid);
154 VATTR_WANTED(&va, va_data_size);
155 VATTR_WANTED(&va, va_nlink);
156 error = EFAULT;
2d21ac55 157 if (vnode_getattr(ref->vp, &va, ref->ctx))
3a60a9f5
A
158 goto out;
159
160 kprintf("vp va_rdev major %d minor %d\n", major(va.va_rdev), minor(va.va_rdev));
161 kprintf("vp va_fsid major %d minor %d\n", major(va.va_fsid), minor(va.va_fsid));
162 kprintf("vp size %qd\n", va.va_data_size);
163
164 if (ref->vp->v_type == VREG)
165 {
166 /* Don't dump files with links. */
167 if (va.va_nlink != 1)
168 goto out;
169
170 device = va.va_fsid;
b0d623f7 171 p1 = &device;
3a60a9f5
A
172 p2 = p;
173 do_ioctl = &file_ioctl;
174 }
175 else if ((ref->vp->v_type == VBLK) || (ref->vp->v_type == VCHR))
176 {
177 /* Partition. */
178 device = va.va_rdev;
179
180 p1 = ref->vp;
2d21ac55 181 p2 = ref->ctx;
3a60a9f5
A
182 do_ioctl = &device_ioctl;
183 }
184 else
185 {
186 /* Don't dump to non-regular files. */
187 error = EFAULT;
188 goto out;
189 }
6d2010ae
A
190 ref->device = device;
191
192 // generate the block list
193
194 error = do_ioctl(p1, p2, DKIOCLOCKPHYSICALEXTENTS, NULL);
195 if (error)
196 goto out;
197 locked = TRUE;
198
199 // get block size
200
201 error = do_ioctl(p1, p2, DKIOCGETBLOCKSIZE, (caddr_t) &blksize);
202 if (error)
203 goto out;
204
205 if (ref->vp->v_type == VREG)
206 filelength = va.va_data_size;
207 else
208 {
209 error = do_ioctl(p1, p2, DKIOCGETBLOCKCOUNT, (caddr_t) &fileblk);
210 if (error)
211 goto out;
212 filelength = fileblk * blksize;
213 }
214
215 f_offset = 0;
216 while (f_offset < filelength)
217 {
218 if (ref->vp->v_type == VREG)
219 {
220 filechunk = 1*1024*1024*1024;
221 daddr64_t blkno;
222
223 error = VNOP_BLOCKMAP(ref->vp, f_offset, filechunk, &blkno, &filechunk, NULL, 0, NULL);
224 if (error)
225 goto out;
226
227 fileblk = blkno * blksize;
228 }
229 else if ((ref->vp->v_type == VBLK) || (ref->vp->v_type == VCHR))
230 {
231 fileblk = f_offset;
232 filechunk = f_offset ? 0 : filelength;
233 }
234
235 physoffset = 0;
236 while (physoffset < filechunk)
237 {
238 dk_physical_extent_t getphysreq;
239 bzero(&getphysreq, sizeof(getphysreq));
240
241 getphysreq.offset = fileblk + physoffset;
242 getphysreq.length = (filechunk - physoffset);
243 error = do_ioctl(p1, p2, DKIOCGETPHYSICALEXTENT, (caddr_t) &getphysreq);
244 if (error)
245 goto out;
246 if (!target)
247 {
248 target = getphysreq.dev;
249 }
250 else if (target != getphysreq.dev)
251 {
252 error = ENOTSUP;
253 goto out;
254 }
255 callback(callback_ref, getphysreq.offset, getphysreq.length);
256 physoffset += getphysreq.length;
257 }
258 f_offset += filechunk;
259 }
260 callback(callback_ref, 0ULL, 0ULL);
261
262 if (ref->vp->v_type == VREG)
263 p1 = &target;
3a60a9f5
A
264
265 // get partition base
266
267 error = do_ioctl(p1, p2, DKIOCGETBASE, (caddr_t) partitionbase_result);
268 if (error)
269 goto out;
270
271 // get block size & constraints
272
273 error = do_ioctl(p1, p2, DKIOCGETBLOCKSIZE, (caddr_t) &blksize);
274 if (error)
275 goto out;
276
277 maxiocount = 1*1024*1024*1024;
278
279 error = do_ioctl(p1, p2, DKIOCGETMAXBLOCKCOUNTREAD, (caddr_t) &count);
280 if (error)
281 count = 0;
282 count *= blksize;
283 if (count && (count < maxiocount))
284 maxiocount = count;
285
286 error = do_ioctl(p1, p2, DKIOCGETMAXBLOCKCOUNTWRITE, (caddr_t) &count);
287 if (error)
288 count = 0;
289 count *= blksize;
290 if (count && (count < maxiocount))
291 maxiocount = count;
292
293 error = do_ioctl(p1, p2, DKIOCGETMAXBYTECOUNTREAD, (caddr_t) &count);
294 if (error)
295 count = 0;
296 if (count && (count < maxiocount))
297 maxiocount = count;
298
299 error = do_ioctl(p1, p2, DKIOCGETMAXBYTECOUNTWRITE, (caddr_t) &count);
300 if (error)
301 count = 0;
302 if (count && (count < maxiocount))
303 maxiocount = count;
304
305 error = do_ioctl(p1, p2, DKIOCGETMAXSEGMENTBYTECOUNTREAD, (caddr_t) &count);
306 if (error)
307 count = 0;
308 if (count && (count < maxiocount))
309 maxiocount = count;
310
311 error = do_ioctl(p1, p2, DKIOCGETMAXSEGMENTBYTECOUNTWRITE, (caddr_t) &count);
312 if (error)
313 count = 0;
314 if (count && (count < maxiocount))
315 maxiocount = count;
316
317 kprintf("max io 0x%qx bytes\n", maxiocount);
318 if (maxiocount_result)
319 *maxiocount_result = maxiocount;
320
6d2010ae
A
321 error = do_ioctl(p1, p2, DKIOCISSOLIDSTATE, (caddr_t)&isssd);
322 if (!error && isssd)
323 flags |= kIOHibernateOptionSSD;
3a60a9f5 324
6d2010ae
A
325 if (partition_device_result)
326 *partition_device_result = device;
327 if (image_device_result)
328 *image_device_result = target;
329 if (flags)
330 *oflags = flags;
3a60a9f5
A
331
332out:
333 kprintf("kern_open_file_for_direct_io(%d)\n", error);
334
6d2010ae
A
335 if (error && locked)
336 {
337 p1 = &device;
338 (void) do_ioctl(p1, p2, DKIOCUNLOCKPHYSICALEXTENTS, NULL);
339 }
340
341 if (error && ref)
342 {
343 if (ref->vp)
344 {
2d21ac55
A
345 vnode_close(ref->vp, FWRITE, ref->ctx);
346 ref->vp = NULLVP;
347 }
2d21ac55
A
348 vfs_context_rele(ref->ctx);
349 kfree(ref, sizeof(struct kern_direct_file_io_ref_t));
350 ref = NULL;
3a60a9f5 351 }
3a60a9f5
A
352 return(ref);
353}
354
355int
356kern_write_file(struct kern_direct_file_io_ref_t * ref, off_t offset, caddr_t addr, vm_size_t len)
357{
358 return (vn_rdwr(UIO_WRITE, ref->vp,
359 addr, len, offset,
b0d623f7 360 UIO_SYSSPACE, IO_SYNC|IO_NODELOCKED|IO_UNIT,
2d21ac55
A
361 vfs_context_ucred(ref->ctx), (int *) 0,
362 vfs_context_proc(ref->ctx)));
3a60a9f5
A
363}
364
365void
6d2010ae
A
366kern_close_file_for_direct_io(struct kern_direct_file_io_ref_t * ref,
367 off_t offset, caddr_t addr, vm_size_t len)
3a60a9f5 368{
6d2010ae 369 int error;
3a60a9f5
A
370 kprintf("kern_close_file_for_direct_io\n");
371
6d2010ae 372 if (!ref) return;
3a60a9f5 373
6d2010ae
A
374 if (ref->vp)
375 {
376 int (*do_ioctl)(void * p1, void * p2, u_long theIoctl, caddr_t result);
377 void * p1;
378 void * p2;
379
380 if (ref->vp->v_type == VREG)
381 {
382 p1 = &ref->device;
383 p2 = kernproc;
384 do_ioctl = &file_ioctl;
385 }
386 else
387 {
388 /* Partition. */
389 p1 = ref->vp;
390 p2 = ref->ctx;
391 do_ioctl = &device_ioctl;
392 }
393 (void) do_ioctl(p1, p2, DKIOCUNLOCKPHYSICALEXTENTS, NULL);
394
395 if (addr && len)
396 {
397 (void) kern_write_file(ref, offset, addr, len);
398 }
399
400 error = vnode_close(ref->vp, FWRITE, ref->ctx);
401
402 ref->vp = NULLVP;
403 kprintf("vnode_close(%d)\n", error);
3a60a9f5 404 }
6d2010ae
A
405 vfs_context_rele(ref->ctx);
406 ref->ctx = NULL;
407 kfree(ref, sizeof(struct kern_direct_file_io_ref_t));
3a60a9f5 408}
2d21ac55 409