X-Git-Url: https://git.saurik.com/apple/xnu.git/blobdiff_plain/de355530ae67247cbd0da700edb3a2a1dae884c2..8ad349bb6ed4a0be06e34c92be0d98b92e078db4:/bsd/kern/kern_symfile.c diff --git a/bsd/kern/kern_symfile.c b/bsd/kern/kern_symfile.c index f4607b9d3..3a8678c89 100644 --- a/bsd/kern/kern_symfile.c +++ b/bsd/kern/kern_symfile.c @@ -1,39 +1,52 @@ /* - * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. - * - * @APPLE_LICENSE_HEADER_START@ - * - * The contents of this file constitute Original Code as defined in and - * are subject to the Apple Public Source License Version 1.1 (the - * "License"). You may not use this file except in compliance with the - * License. Please obtain a copy of the License at - * http://www.apple.com/publicsource and read it before using this file. + * Copyright (c) 2006 Apple Computer, Inc. All Rights Reserved. * - * This Original Code and all software distributed under the License are - * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the - * License for the specific language governing rights and limitations - * under the License. + * @APPLE_LICENSE_OSREFERENCE_HEADER_START@ * - * @APPLE_LICENSE_HEADER_END@ + * This file contains Original Code and/or Modifications of Original Code + * as defined in and that are subject to the Apple Public Source License + * Version 2.0 (the 'License'). You may not use this file except in + * compliance with the License. The rights granted to you under the + * License may not be used to create, or enable the creation or + * redistribution of, unlawful or unlicensed copies of an Apple operating + * system, or to circumvent, violate, or enable the circumvention or + * violation of, any terms of an Apple operating system software license + * agreement. + * + * Please obtain a copy of the License at + * http://www.opensource.apple.com/apsl/ and read it before using this + * file. + * + * The Original Code and all software distributed under the License are + * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. + * Please see the License for the specific language governing rights and + * limitations under the License. + * + * @APPLE_LICENSE_OSREFERENCE_HEADER_END@ */ /* Copyright (c) 1998 Apple Computer, Inc. All rights reserved. * * File: bsd/kern/kern_symfile.c * - * This file contains creates a dummy symbol file for mach_kernel based on - * the symbol table information passed by the SecondaryLoader/PlatformExpert. - * This allows us to correctly link other executables (drivers, etc) against the - * the kernel in cases where the kernel image on the root device does not match - * the live kernel. This can occur during net-booting where the actual kernel - * image is obtained from the network via tftp rather than the root - * device. + * This file contains creates a dummy symbol file for mach_kernel + * based on the symbol table information passed by the + * SecondaryLoader/PlatformExpert. This allows us to correctly + * link other executables (drivers, etc) against the the kernel in + * cases where the kernel image on the root device does not match + * the live kernel. This can occur during net-booting where the + * actual kernel image is obtained from the network via tftp rather + * than the root device. * - * If a symbol table is available, then the file /mach.sym will be created - * containing a Mach Header and a LC_SYMTAB load command followed by the - * the symbol table data for mach_kernel. + * If a symbol table is available, then the file /mach.sym will be + * created containing a Mach Header and a LC_SYMTAB load command + * followed by the the symbol table data for mach_kernel. + * + * NOTE: This file supports only 32 bit kernels at the present time; + * adding support for 64 bit kernels is possible, but is not + * necessary at the present time. * * HISTORY * @@ -47,21 +60,26 @@ #include #include #include -#include -#include +#include +#include +#include #include #include -#include #include -#include +#include #include #include #include +#include +#include #include #include +#include #include +#include +#include extern unsigned char rootdevice[]; extern struct mach_header _mh_execute_header; @@ -73,15 +91,15 @@ extern int IODTGetLoaderInfo(char *key, void **infoAddr, int *infoSize); extern void IODTFreeLoaderInfo(char *key, void *infoAddr, int infoSize); /* - * + * Can only operate against currently running 32 bit mach_kernel */ -static int output_kernel_symbols(struct proc *p) +static int +output_kernel_symbols(struct proc *p) { struct vnode *vp; - struct pcred *pcred = p->p_cred; - struct ucred *cred = pcred->pc_ucred; - struct nameidata nd; - struct vattr vattr; + kauth_cred_t cred = p->p_ucred; /* XXX */ + struct vnode_attr va; + struct vfs_context context; struct load_command *cmd; struct mach_header *orig_mh, *mh; struct segment_command *orig_ds, *orig_ts, *orig_le, *sg; @@ -90,9 +108,9 @@ static int output_kernel_symbols(struct proc *p) struct nlist *sym; vm_size_t orig_mhsize, orig_st_size; vm_offset_t header; - vm_size_t header_size; + vm_size_t header_size = 0; /* out: protected by header */ int error, error1; - int i, j; + unsigned int i, j; caddr_t addr; vm_offset_t offset; int rc_mh, rc_sc; @@ -107,38 +125,39 @@ static int output_kernel_symbols(struct proc *p) // Dispose of unnecessary gumf, the booter doesn't need to load these rc_mh = IODTGetLoaderInfo("Kernel-__HEADER", (void **)&orig_mh, &orig_mhsize); - if (rc_mh && orig_mh) + if (rc_mh == 0 && orig_mh) IODTFreeLoaderInfo("Kernel-__HEADER", - (void *)orig_mh, round_page(orig_mhsize)); + (void *)orig_mh, round_page_32(orig_mhsize)); rc_sc = IODTGetLoaderInfo("Kernel-__SYMTAB", (void **) &orig_st, &orig_st_size); - if (rc_sc && orig_st) + if (rc_sc == 0 && orig_st) IODTFreeLoaderInfo("Kernel-__SYMTAB", - (void *)orig_st, round_page(orig_st_size)); + (void *)orig_st, round_page_32(orig_st_size)); - if (pcred->p_svuid != pcred->p_ruid || pcred->p_svgid != pcred->p_rgid) + if (cred->cr_svuid != cred->cr_ruid || cred->cr_svgid != cred->cr_rgid) goto out; // Check to see if the root is 'e' or 'n', is this a test for network? if (rootdevice[0] == 'e' && rootdevice[1] == 'n') goto out; - NDINIT(&nd, LOOKUP, FOLLOW, UIO_SYSSPACE, "mach.sym", p); - if((error = vn_open(&nd, O_CREAT | FWRITE, S_IRUSR | S_IRGRP | S_IROTH))) goto out; + context.vc_proc = p; + context.vc_ucred = cred; + + if ((error = vnode_open("mach.sym", (O_CREAT | FWRITE), (S_IRUSR | S_IRGRP | S_IROTH), 0, &vp, &context))) + goto out; - vp = nd.ni_vp; - /* Don't dump to non-regular files or files with links. */ error = EFAULT; - if (vp->v_type != VREG || VOP_GETATTR(vp, &vattr, cred, p) - || vattr.va_nlink != 1) + VATTR_INIT(&va); + VATTR_WANTED(&va, va_nlink); + if ((vp->v_type != VREG) || vnode_getattr(vp, &va, &context) || (va.va_nlink != 1)) goto out; - VATTR_NULL(&vattr); - vattr.va_size = 0; - VOP_LEASE(vp, p, cred, LEASE_WRITE); - VOP_SETATTR(vp, &vattr, cred, p); + VATTR_INIT(&va); /* better to do it here than waste more stack in vnode_getsize */ + VATTR_SET(&va, va_data_size, 0); + vnode_setattr(vp, &va, &context); p->p_acflag |= ACORE; // If the file type is MH_EXECUTE then this must be a kernel @@ -149,14 +168,14 @@ static int output_kernel_symbols(struct proc *p) cmd = (struct load_command *) &orig_mh[1]; for (i = 0; i < orig_mh->ncmds; i++) { if (cmd->cmd == LC_SEGMENT) { - struct segment_command *sg = (struct segment_command *) cmd; + struct segment_command *orig_sg = (struct segment_command *) cmd; - if (!strcmp(SEG_TEXT, sg->segname)) - orig_ts = sg; - else if (!strcmp(SEG_DATA, sg->segname)) - orig_ds = sg; - else if (!strcmp(SEG_LINKEDIT, sg->segname)) - orig_le = sg; + if (!strcmp(SEG_TEXT, orig_sg->segname)) + orig_ts = orig_sg; + else if (!strcmp(SEG_DATA, orig_sg->segname)) + orig_ds = orig_sg; + else if (!strcmp(SEG_LINKEDIT, orig_sg->segname)) + orig_le = orig_sg; } else if (cmd->cmd == LC_SYMTAB) orig_st = (struct symtab_command *) cmd; @@ -183,7 +202,7 @@ static int output_kernel_symbols(struct proc *p) + orig_ds->cmdsize + sizeof(struct symtab_command); - (void) kmem_alloc_wired(kernel_map, + (void) kmem_alloc(kernel_map, (vm_offset_t *) &header, (vm_size_t) header_size); if (header) @@ -234,7 +253,7 @@ static int output_kernel_symbols(struct proc *p) const_text = se; } } - offset = round_page((vm_address_t) offset); + offset = round_page(offset); // Now copy of the __DATA segment load command, the image need // not be stored to disk nobody needs it, yet! @@ -285,7 +304,7 @@ static int output_kernel_symbols(struct proc *p) * Write out the load commands at the beginning of the file. */ error = vn_rdwr(UIO_WRITE, vp, (caddr_t) mh, header_size, (off_t) 0, - UIO_SYSSPACE, IO_NODELOCKED|IO_UNIT, cred, (int *) 0, p); + UIO_SYSSPACE32, IO_NODELOCKED|IO_UNIT, cred, (int *) 0, p); if (error) goto out; @@ -294,7 +313,7 @@ static int output_kernel_symbols(struct proc *p) */ error = vn_rdwr(UIO_WRITE, vp, (caddr_t) const_text->addr, const_text->size, const_text->offset, - UIO_SYSSPACE, IO_NODELOCKED|IO_UNIT, cred, (int *) 0, p); + UIO_SYSSPACE32, IO_NODELOCKED|IO_UNIT, cred, (int *) 0, p); if (error) goto out; @@ -304,17 +323,13 @@ static int output_kernel_symbols(struct proc *p) offset = st->nsyms * sizeof(struct nlist) + st->strsize; // symtab size error = vn_rdwr(UIO_WRITE, vp, (caddr_t) orig_le->vmaddr, offset, st->symoff, - UIO_SYSSPACE, IO_NODELOCKED|IO_UNIT, cred, (int *) 0, p); - if (error) - goto out; - + UIO_SYSSPACE32, IO_NODELOCKED|IO_UNIT, cred, (int *) 0, p); out: if (header) kmem_free(kernel_map, header, header_size); if (vp) { - VOP_UNLOCK(vp, 0, p); - error1 = vn_close(vp, FWRITE, cred, p); + error1 = vnode_close(vp, FWRITE, &context); if (!error) error = error1; } @@ -334,3 +349,231 @@ int get_kernel_symfile(struct proc *p, char **symfile) return error_code; } + +struct kern_direct_file_io_ref_t +{ + struct vfs_context context; + struct vnode *vp; +}; + + +static int file_ioctl(void * p1, void * p2, int theIoctl, caddr_t result) +{ + dev_t device = (dev_t) p1; + + return ((*bdevsw[major(device)].d_ioctl) + (device, theIoctl, result, S_IFBLK, p2)); +} + +static int device_ioctl(void * p1, __unused void * p2, int theIoctl, caddr_t result) +{ + return (VNOP_IOCTL(p1, theIoctl, result, 0, p2)); +} + +struct kern_direct_file_io_ref_t * +kern_open_file_for_direct_io(const char * name, + kern_get_file_extents_callback_t callback, + void * callback_ref, + dev_t * device_result, + uint64_t * partitionbase_result, + uint64_t * maxiocount_result) +{ + struct kern_direct_file_io_ref_t * ref; + + struct proc *p; + struct ucred *cred; + struct vnode_attr va; + int error; + off_t f_offset; + uint32_t blksize; + uint64_t size; + dev_t device; + off_t maxiocount, count; + + int (*do_ioctl)(void * p1, void * p2, int theIoctl, caddr_t result); + void * p1; + void * p2; + + error = EFAULT; + + ref = (struct kern_direct_file_io_ref_t *) kalloc(sizeof(struct kern_direct_file_io_ref_t)); + if (!ref) + { + error = EFAULT; + goto out; + } + + ref->vp = NULL; + p = current_proc(); // kernproc; + cred = p->p_ucred; + ref->context.vc_proc = p; + ref->context.vc_ucred = cred; + + if ((error = vnode_open(name, (O_CREAT | FWRITE), (0), 0, &ref->vp, &ref->context))) + goto out; + + VATTR_INIT(&va); + VATTR_WANTED(&va, va_rdev); + VATTR_WANTED(&va, va_fsid); + VATTR_WANTED(&va, va_data_size); + VATTR_WANTED(&va, va_nlink); + error = EFAULT; + if (vnode_getattr(ref->vp, &va, &ref->context)) + goto out; + + kprintf("vp va_rdev major %d minor %d\n", major(va.va_rdev), minor(va.va_rdev)); + kprintf("vp va_fsid major %d minor %d\n", major(va.va_fsid), minor(va.va_fsid)); + kprintf("vp size %qd\n", va.va_data_size); + + if (ref->vp->v_type == VREG) + { + /* Don't dump files with links. */ + if (va.va_nlink != 1) + goto out; + + device = va.va_fsid; + p1 = (void *) device; + p2 = p; + do_ioctl = &file_ioctl; + } + else if ((ref->vp->v_type == VBLK) || (ref->vp->v_type == VCHR)) + { + /* Partition. */ + device = va.va_rdev; + + p1 = ref->vp; + p2 = &ref->context; + do_ioctl = &device_ioctl; + } + else + { + /* Don't dump to non-regular files. */ + error = EFAULT; + goto out; + } + + // get partition base + + error = do_ioctl(p1, p2, DKIOCGETBASE, (caddr_t) partitionbase_result); + if (error) + goto out; + + // get block size & constraints + + error = do_ioctl(p1, p2, DKIOCGETBLOCKSIZE, (caddr_t) &blksize); + if (error) + goto out; + + maxiocount = 1*1024*1024*1024; + + error = do_ioctl(p1, p2, DKIOCGETMAXBLOCKCOUNTREAD, (caddr_t) &count); + if (error) + count = 0; + count *= blksize; + if (count && (count < maxiocount)) + maxiocount = count; + + error = do_ioctl(p1, p2, DKIOCGETMAXBLOCKCOUNTWRITE, (caddr_t) &count); + if (error) + count = 0; + count *= blksize; + if (count && (count < maxiocount)) + maxiocount = count; + + error = do_ioctl(p1, p2, DKIOCGETMAXBYTECOUNTREAD, (caddr_t) &count); + if (error) + count = 0; + if (count && (count < maxiocount)) + maxiocount = count; + + error = do_ioctl(p1, p2, DKIOCGETMAXBYTECOUNTWRITE, (caddr_t) &count); + if (error) + count = 0; + if (count && (count < maxiocount)) + maxiocount = count; + + error = do_ioctl(p1, p2, DKIOCGETMAXSEGMENTBYTECOUNTREAD, (caddr_t) &count); + if (error) + count = 0; + if (count && (count < maxiocount)) + maxiocount = count; + + error = do_ioctl(p1, p2, DKIOCGETMAXSEGMENTBYTECOUNTWRITE, (caddr_t) &count); + if (error) + count = 0; + if (count && (count < maxiocount)) + maxiocount = count; + + kprintf("max io 0x%qx bytes\n", maxiocount); + if (maxiocount_result) + *maxiocount_result = maxiocount; + + // generate the block list + + error = 0; + if (ref->vp->v_type == VREG) + { + f_offset = 0; + while(f_offset < (off_t) va.va_data_size) + { + size_t io_size = 1*1024*1024*1024; + daddr64_t blkno; + + error = VNOP_BLOCKMAP(ref->vp, f_offset, io_size, &blkno, (size_t *)&io_size, NULL, 0, NULL); + if (error) + goto out; + callback(callback_ref, ((uint64_t) blkno) * blksize, (uint64_t) io_size); + f_offset += io_size; + } + callback(callback_ref, 0ULL, 0ULL); + } + else if ((ref->vp->v_type == VBLK) || (ref->vp->v_type == VCHR)) + { + error = do_ioctl(p1, p2, DKIOCGETBLOCKCOUNT, (caddr_t) &size); + if (error) + goto out; + size *= blksize; + callback(callback_ref, 0ULL, size); + callback(callback_ref, size, 0ULL); + } + + if (device_result) + *device_result = device; + +out: + kprintf("kern_open_file_for_direct_io(%d)\n", error); + + if (error && ref) { + if (ref->vp) + vnode_close(ref->vp, FWRITE, &ref->context); + + kfree(ref, sizeof(struct kern_direct_file_io_ref_t)); + } + + return(ref); +} + +int +kern_write_file(struct kern_direct_file_io_ref_t * ref, off_t offset, caddr_t addr, vm_size_t len) +{ + return (vn_rdwr(UIO_WRITE, ref->vp, + addr, len, offset, + UIO_SYSSPACE32, IO_SYNC|IO_NODELOCKED|IO_UNIT, + ref->context.vc_ucred, (int *) 0, ref->context.vc_proc)); +} + +void +kern_close_file_for_direct_io(struct kern_direct_file_io_ref_t * ref) +{ + kprintf("kern_close_file_for_direct_io\n"); + + if (ref) { + int error; + + if (ref->vp) { + error = vnode_close(ref->vp, FWRITE, &ref->context); + kprintf("vnode_close(%d)\n", error); + } + kfree(ref, sizeof(struct kern_direct_file_io_ref_t)); + } +}