]> git.saurik.com Git - apple/xnu.git/blob - bsd/kern/kern_panicinfo.c
xnu-1504.9.17.tar.gz
[apple/xnu.git] / bsd / kern / kern_panicinfo.c
1 /*
2 * Copyright (c) 2002-2006 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 <sys/param.h>
30 #include <sys/fcntl.h>
31 #include <sys/malloc.h>
32 #include <sys/proc.h>
33 #include <sys/sysctl.h>
34 #include <sys/vnode.h>
35 #include <sys/vm.h>
36 #include <sys/systm.h>
37
38 #include <mach/mach_types.h>
39 #include <mach/kern_return.h>
40 #include <kern/kern_types.h>
41 #include <vm/vm_kern.h>
42
43
44 /* prototypes not exported by osfmk/console. */
45 extern void panic_dialog_test( void );
46 extern int panic_dialog_set_image( const unsigned char * ptr, unsigned int size );
47 extern void panic_dialog_get_image( unsigned char ** ptr, unsigned int * size );
48
49 /* make the compiler happy */
50 extern int sysctl_dopanicinfo(int *, u_int, user_addr_t, size_t *, user_addr_t, size_t, struct proc *);
51
52
53 #define PANIC_IMAGE_SIZE_LIMIT (32 * 4096) /* 128K - Maximum amount of memory consumed for the panic UI */
54 #define KERN_PANICINFO_TEST (KERN_PANICINFO_IMAGE+2) /* Allow the panic UI to be tested by root without causing a panic */
55
56 /* Local data */
57 static int image_size_limit = PANIC_IMAGE_SIZE_LIMIT;
58
59 __private_extern__ int
60 sysctl_dopanicinfo(int *name, u_int namelen, user_addr_t oldp, size_t *oldlenp,
61 user_addr_t newp, size_t newlen, struct proc *p)
62 {
63 int error = 0;
64 vm_offset_t newimage = (vm_offset_t )NULL;
65 kern_return_t kret;
66 unsigned char * prev_image_ptr;
67 unsigned int prev_image_size;
68
69 /* all sysctl names at this level are terminal */
70 if (namelen != 1)
71 return (ENOTDIR); /* overloaded */
72
73 if ( (error = proc_suser(p)) ) /* must be super user to muck with image */
74 return (error);
75
76 switch (name[0]) {
77 default:
78 return (ENOTSUP);
79
80 case KERN_PANICINFO_TEST:
81
82 panic_dialog_test();
83 return (0);
84
85 case KERN_PANICINFO_MAXSIZE:
86
87 /* return the image size limits */
88
89 newlen = 0;
90 newp = USER_ADDR_NULL;
91
92 error = sysctl_int(oldp, oldlenp, newp, newlen, &image_size_limit);
93
94 return (error);
95
96 case KERN_PANICINFO_IMAGE:
97
98 /* If we have a new image, allocate wired kernel memory and copy it in from user space */
99 if ( newp != USER_ADDR_NULL ) {
100
101 /* check the length of the incoming image before allocating space for it. */
102 if ( newlen > (size_t)image_size_limit )
103 return (ENOMEM);
104
105 /* allocate some kernel wired memory for the new image */
106 kret = kmem_alloc(kernel_map, &newimage, (vm_size_t)round_page(newlen));
107
108 if (kret != KERN_SUCCESS) {
109 switch (kret) {
110 default:
111 error = EINVAL;
112 break;
113 case KERN_NO_SPACE:
114 case KERN_RESOURCE_SHORTAGE:
115 error = ENOMEM;
116 break;
117 case KERN_PROTECTION_FAILURE:
118 error = EPERM;
119 break;
120 }
121
122 return (error);
123 }
124
125 /* copy the image in from user space */
126 if ( (error = copyin(newp, (char *) newimage, newlen)) )
127 goto errout;
128
129 } else { /* setup to make the default image active */
130
131 newimage = (vm_offset_t )NULL;
132 newlen = 0;
133 }
134
135 /* get the current image location and size */
136 panic_dialog_get_image( &prev_image_ptr, &prev_image_size );
137
138 /* did the caller request a copy of the previous image ? */
139 if ( oldp != USER_ADDR_NULL ) {
140 if ( *oldlenp < prev_image_size ) {
141 error = ERANGE;
142 goto errout;
143 }
144
145 /* copy the image to user space or zero the size if the default image is active */
146 if ( prev_image_ptr != NULL ) {
147 if ( (error = copyout( prev_image_ptr, oldp, prev_image_size )) )
148 goto errout;
149
150 *oldlenp = prev_image_size;
151 }
152 else /* tell the user that the default image is active */
153 *oldlenp = 0;
154 }
155
156 /* Make the new image active, or reactivate the default image.
157 But, handle the special case of asking for the current image
158 without changing the current image.
159 */
160
161 if ( !(oldp && newp == USER_ADDR_NULL) ) {
162 if ( (error = panic_dialog_set_image( (unsigned char *) newimage, newlen )) )
163 goto errout;
164
165 /* free the wired memory used by the previous image */
166 if ( prev_image_ptr != NULL ) {
167 (void)kmem_free(kernel_map, (vm_offset_t) prev_image_ptr, (vm_size_t)round_page(prev_image_size));
168 printf("Panic UI memory freed (%p)\n", (void *)round_page(prev_image_size));
169 }
170 }
171
172 return (0);
173
174 errout:
175 if ( newimage != (vm_offset_t )NULL )
176 (void)kmem_free(kernel_map, newimage, (vm_size_t)round_page(newlen));
177
178 return (error);
179 }
180 }