]>
Commit | Line | Data |
---|---|---|
9bccf70c A |
1 | /* |
2 | * Copyright (c) 2002 Apple Computer, Inc. All rights reserved. | |
3 | * | |
8ad349bb | 4 | * @APPLE_LICENSE_OSREFERENCE_HEADER_START@ |
9bccf70c | 5 | * |
8ad349bb 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 | |
10 | * License may not be used to create, or enable the creation or | |
11 | * redistribution of, unlawful or unlicensed copies of an Apple operating | |
12 | * system, or to circumvent, violate, or enable the circumvention or | |
13 | * violation of, any terms of an Apple operating system software license | |
14 | * agreement. | |
15 | * | |
16 | * Please obtain a copy of the License at | |
17 | * http://www.opensource.apple.com/apsl/ and read it before using this | |
18 | * file. | |
19 | * | |
20 | * The Original Code and all software distributed under the License are | |
21 | * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER | |
22 | * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, | |
23 | * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, | |
24 | * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. | |
25 | * Please see the License for the specific language governing rights and | |
26 | * limitations under the License. | |
27 | * | |
28 | * @APPLE_LICENSE_OSREFERENCE_HEADER_END@ | |
9bccf70c A |
29 | */ |
30 | ||
31 | #include <sys/param.h> | |
32 | #include <sys/fcntl.h> | |
33 | #include <sys/malloc.h> | |
9bccf70c | 34 | #include <sys/proc.h> |
9bccf70c A |
35 | #include <sys/sysctl.h> |
36 | #include <sys/vnode.h> | |
37 | #include <sys/vm.h> | |
91447636 | 38 | #include <sys/systm.h> |
9bccf70c | 39 | |
91447636 | 40 | #include <mach/mach_types.h> |
9bccf70c | 41 | #include <mach/kern_return.h> |
91447636 A |
42 | #include <kern/kern_types.h> |
43 | #include <vm/vm_kern.h> | |
9bccf70c | 44 | |
9bccf70c | 45 | |
91447636 A |
46 | /* prototypes not exported by osfmk/console. */ |
47 | extern void panic_dialog_test( void ); | |
48 | extern int panic_dialog_set_image( const unsigned char * ptr, unsigned int size ); | |
49 | extern void panic_dialog_get_image( unsigned char ** ptr, unsigned int * size ); | |
9bccf70c | 50 | |
91447636 A |
51 | /* make the compiler happy */ |
52 | extern int sysctl_dopanicinfo(int *, u_int, user_addr_t, size_t *, user_addr_t, size_t, struct proc *); | |
9bccf70c | 53 | |
9bccf70c | 54 | |
91447636 A |
55 | #define PANIC_IMAGE_SIZE_LIMIT (32 * 4096) /* 128K - Maximum amount of memory consumed for the panic UI */ |
56 | #define KERN_PANICINFO_TEST (KERN_PANICINFO_IMAGE+2) /* Allow the panic UI to be tested by root without causing a panic */ | |
9bccf70c | 57 | |
91447636 A |
58 | /* Local data */ |
59 | static int image_size_limit = PANIC_IMAGE_SIZE_LIMIT; | |
9bccf70c A |
60 | |
61 | __private_extern__ int | |
62 | sysctl_dopanicinfo(name, namelen, oldp, oldlenp, newp, newlen, p) | |
63 | int *name; | |
64 | u_int namelen; | |
91447636 | 65 | user_addr_t oldp; |
9bccf70c | 66 | size_t *oldlenp; |
91447636 | 67 | user_addr_t newp; |
9bccf70c A |
68 | size_t newlen; |
69 | struct proc *p; | |
70 | { | |
71 | int error = 0; | |
91447636 A |
72 | vm_offset_t newimage = (vm_offset_t )NULL; |
73 | kern_return_t kret; | |
74 | unsigned char * prev_image_ptr; | |
75 | unsigned int prev_image_size; | |
76 | ||
9bccf70c A |
77 | |
78 | /* all sysctl names at this level are terminal */ | |
79 | if (namelen != 1) | |
80 | return (ENOTDIR); /* overloaded */ | |
81 | ||
91447636 A |
82 | if ( (error = proc_suser(p)) ) /* must be super user to muck with image */ |
83 | return (error); | |
84 | ||
9bccf70c A |
85 | switch (name[0]) { |
86 | default: | |
91447636 A |
87 | return (ENOTSUP); |
88 | ||
89 | case KERN_PANICINFO_TEST: | |
90 | ||
91 | panic_dialog_test(); | |
92 | return (0); | |
93 | ||
9bccf70c | 94 | case KERN_PANICINFO_MAXSIZE: |
91447636 A |
95 | |
96 | /* return the image size limits */ | |
97 | ||
98 | newlen = 0; | |
99 | newp = USER_ADDR_NULL; | |
100 | ||
101 | error = sysctl_int(oldp, oldlenp, newp, newlen, &image_size_limit); | |
102 | ||
9bccf70c A |
103 | return (error); |
104 | ||
91447636 A |
105 | case KERN_PANICINFO_IMAGE: |
106 | ||
107 | /* If we have a new image, allocate wired kernel memory and copy it in from user space */ | |
108 | if ( newp != USER_ADDR_NULL ) { | |
109 | ||
110 | /* check the length of the incoming image before allocating space for it. */ | |
111 | if ( newlen > (size_t)image_size_limit ) | |
112 | return (ENOMEM); | |
113 | ||
114 | /* allocate some kernel wired memory for the new image */ | |
115 | kret = kmem_alloc(kernel_map, &newimage, (vm_size_t)round_page_32(newlen)); | |
116 | ||
117 | if (kret != KERN_SUCCESS) { | |
118 | switch (kret) { | |
119 | default: | |
120 | error = EINVAL; | |
121 | break; | |
122 | case KERN_NO_SPACE: | |
123 | case KERN_RESOURCE_SHORTAGE: | |
124 | error = ENOMEM; | |
125 | break; | |
126 | case KERN_PROTECTION_FAILURE: | |
127 | error = EPERM; | |
128 | break; | |
129 | } | |
130 | ||
131 | return (error); | |
132 | } | |
133 | ||
134 | /* copy the image in from user space */ | |
135 | if ( (error = copyin(newp, (char *) newimage, newlen)) ) | |
9bccf70c A |
136 | goto errout; |
137 | ||
91447636 A |
138 | } else { /* setup to make the default image active */ |
139 | ||
140 | newimage = (vm_offset_t )NULL; | |
141 | newlen = 0; | |
142 | } | |
143 | ||
144 | /* get the current image location and size */ | |
145 | panic_dialog_get_image( &prev_image_ptr, &prev_image_size ); | |
146 | ||
147 | /* did the caller request a copy of the previous image ? */ | |
148 | if ( oldp != USER_ADDR_NULL ) { | |
149 | if ( *oldlenp < prev_image_size ) { | |
150 | error = ERANGE; | |
151 | goto errout; | |
9bccf70c A |
152 | } |
153 | ||
91447636 A |
154 | /* copy the image to user space or zero the size if the default image is active */ |
155 | if ( prev_image_ptr != NULL ) { | |
156 | if ( (error = copyout( prev_image_ptr, oldp, prev_image_size )) ) | |
157 | goto errout; | |
9bccf70c | 158 | |
91447636 A |
159 | *oldlenp = prev_image_size; |
160 | } | |
161 | else /* tell the user that the default image is active */ | |
162 | *oldlenp = 0; | |
163 | } | |
9bccf70c | 164 | |
91447636 A |
165 | /* Make the new image active, or reactivate the default image. |
166 | But, handle the special case of asking for the current image | |
167 | without changing the current image. | |
168 | */ | |
9bccf70c | 169 | |
91447636 A |
170 | if ( !(oldp && newp == USER_ADDR_NULL) ) { |
171 | if ( (error = panic_dialog_set_image( (unsigned char *) newimage, newlen )) ) | |
172 | goto errout; | |
9bccf70c | 173 | |
91447636 A |
174 | /* free the wired memory used by the previous image */ |
175 | if ( prev_image_ptr != NULL ) { | |
176 | (void)kmem_free(kernel_map, (vm_offset_t) prev_image_ptr, (vm_size_t)round_page_32(prev_image_size)); | |
177 | printf("Panic UI memory freed (%d)\n", round_page_32(prev_image_size)); | |
178 | } | |
9bccf70c | 179 | } |
91447636 A |
180 | |
181 | return (0); | |
182 | ||
9bccf70c | 183 | errout: |
91447636 A |
184 | if ( newimage != (vm_offset_t )NULL ) |
185 | (void)kmem_free(kernel_map, newimage, (vm_size_t)round_page_32(newlen)); | |
186 | ||
9bccf70c A |
187 | return (error); |
188 | } | |
189 | } |