#include <sys/param.h>
#include <sys/fcntl.h>
#include <sys/malloc.h>
#include <sys/proc.h>
#include <sys/sysctl.h>
#include <sys/vnode.h>
#include <sys/vm.h>
#include <sys/systm.h>
#include <mach/mach_types.h>
#include <mach/kern_return.h>
#include <kern/kern_types.h>
#include <vm/vm_kern.h>
extern void panic_dialog_test( void );
extern int panic_dialog_set_image( const unsigned char * ptr, unsigned int size );
extern void panic_dialog_get_image( unsigned char ** ptr, unsigned int * size );
extern int sysctl_dopanicinfo(int *, u_int, user_addr_t, size_t *, user_addr_t, size_t, struct proc *);
#define PANIC_IMAGE_SIZE_LIMIT (32 * 4096)
#define KERN_PANICINFO_TEST (KERN_PANICINFO_IMAGE+2)
static int image_size_limit = PANIC_IMAGE_SIZE_LIMIT;
__private_extern__ int
sysctl_dopanicinfo(int *name, u_int namelen, user_addr_t oldp, size_t *oldlenp,
user_addr_t newp, size_t newlen, struct proc *p)
{
int error = 0;
vm_offset_t newimage = (vm_offset_t )NULL;
kern_return_t kret;
unsigned char * prev_image_ptr;
unsigned int prev_image_size;
if (namelen != 1)
return (ENOTDIR);
if ( (error = proc_suser(p)) )
return (error);
switch (name[0]) {
default:
return (ENOTSUP);
case KERN_PANICINFO_TEST:
panic_dialog_test();
return (0);
case KERN_PANICINFO_MAXSIZE:
newlen = 0;
newp = USER_ADDR_NULL;
error = sysctl_int(oldp, oldlenp, newp, newlen, &image_size_limit);
return (error);
case KERN_PANICINFO_IMAGE:
if ( newp != USER_ADDR_NULL ) {
if ( newlen > (size_t)image_size_limit )
return (ENOMEM);
kret = kmem_alloc(kernel_map, &newimage, (vm_size_t)round_page(newlen));
if (kret != KERN_SUCCESS) {
switch (kret) {
default:
error = EINVAL;
break;
case KERN_NO_SPACE:
case KERN_RESOURCE_SHORTAGE:
error = ENOMEM;
break;
case KERN_PROTECTION_FAILURE:
error = EPERM;
break;
}
return (error);
}
if ( (error = copyin(newp, (char *) newimage, newlen)) )
goto errout;
} else {
newimage = (vm_offset_t )NULL;
newlen = 0;
}
panic_dialog_get_image( &prev_image_ptr, &prev_image_size );
if ( oldp != USER_ADDR_NULL ) {
if ( *oldlenp < prev_image_size ) {
error = ERANGE;
goto errout;
}
if ( prev_image_ptr != NULL ) {
if ( (error = copyout( prev_image_ptr, oldp, prev_image_size )) )
goto errout;
*oldlenp = prev_image_size;
}
else
*oldlenp = 0;
}
if ( !(oldp && newp == USER_ADDR_NULL) ) {
if ( (error = panic_dialog_set_image( (unsigned char *) newimage, newlen )) )
goto errout;
if ( prev_image_ptr != NULL ) {
(void)kmem_free(kernel_map, (vm_offset_t) prev_image_ptr, (vm_size_t)round_page(prev_image_size));
printf("Panic UI memory freed (%p)\n", (void *)round_page(prev_image_size));
}
}
return (0);
errout:
if ( newimage != (vm_offset_t )NULL )
(void)kmem_free(kernel_map, newimage, (vm_size_t)round_page(newlen));
return (error);
}
}