File:  [NeXTSTEP 3.3 examples] / Examples / UNIX / LKSOutOfLineData / KernelServer / mydriver_main.c
Revision 1.1.1.1 (vendor branch): download - view: text, annotated - select for diffs
Tue Apr 24 17:48:25 2018 UTC (8 years, 1 month ago) by root
Branches: NeXT, MAIN
CVS tags: NeXTSTEP33, HEAD
Sample Programs from NeXSTEP 3.3

/* mydriver_main.c:  major functions of mydriver */

#import <kernserv/kern_server_types.h>
#import <kernserv/prototypes.h>
#import <ansi/string.h>
#import "../Library/mydefs.h"

kern_server_t instance;

/* Pointer to hold local data in the kernel_task's vm */
static user_data_t local_data;

/* mydriver_init:  Called when mydriver is loaded. */
void mydriver_init(void)
{
    kern_return_t r;
    port_t kernel_task = kern_serv_kernel_task_port();	

    //
    // Get a page of publically readable vm to be used to access the mig
    // messages out of line data.  Also used to hold data across import
    // and export calls.
    //
    r = vm_allocate
	(kernel_task, (vm_address_t *) &local_data, page_size, TRUE);
    if (r != KERN_SUCCESS)
    {
	printf("Call to vm_allocate failed %d\n", r);
	local_data = NULL;
    }

    //
    // Clear the newly acquired memory
    //
    memset(local_data, '\0', page_size);
    
    printf("My driver loaded\n");
}


/* mydriver_signoff:  Called when mydriver is unloaded. */
void mydriver_signoff(void)
{
    kern_return_t r;
    port_t kernel_task = kern_serv_kernel_task_port();	

    // Deallocate the kernel vm's local_data buffer
    r = vm_deallocate(kernel_task, (vm_address_t) local_data, page_size);
    if (r != KERN_SUCCESS)
    {
	printf("Call to vm_deallocate failed %d\n", r);
	local_data = NULL;
    }
    
    printf("My driver unloaded\n\n");
}

/* mydriver_import:  Called by mydriver_server, which was created by MiG. */
kern_return_t mydriver_import
    (port_t server, in_user_data_t user_data, unsigned int length)
{
    kern_return_t r;
    user_data_t tmp;
    port_t kernel_task = kern_serv_kernel_task_port();	

    if (!local_data)
	return KERN_FAILURE;

    //
    // Warning:  Loadable kernel servers run outside of the kernel task,
    // even though they use the kernel address map.
    //
    // This means that we have to get the task_self's user_data into the
    // kernel's vm.  To do this we have to, counterintuitively, write the
    // received data into our previously acquired vm page (kernel_task).
    //
    r = vm_write((vm_task_t) kernel_task, (vm_address_t) local_data,
	(pointer_t) user_data, page_size);

    if (r == KERN_SUCCESS)
    {
	tmp = local_data;
	printf("\nTrying to access data.\n");
	printf("First  data element is: %c\n", *tmp++);
	printf("Second data element is: %c\n", *tmp++);
	printf("Third  data element is: %c\n", *tmp++);
	printf("Fourth data element is: %c\n", *tmp++);
	printf("Fifth  data element is: %c\n", *tmp++);
	
	printf("Contents of data are: %s\n", local_data);
    }
    else switch(r)
    {
    case KERN_INVALID_ARGUMENT:
	    printf("vm_write: KERN_INVALID_ARGUMENT %d\n", r);
	    break;
    case KERN_PROTECTION_FAILURE:
	    printf("vm_write: KERN_PROTECTION_FAILURE %d\n", r);
	    break;
    case KERN_INVALID_ADDRESS:
	    printf("vm_write: KERN_INVALID_ADDRESS %d\n", r);
	    break;
    default:
	    printf("Call to vm_write failed %d\n", r);
    }
    
    // 
    // Remove the out_of_band data from the kernel server task's vm.
    // Otherwise we would have a memory leak across the mach message interface.
    //
    r = vm_deallocate(task_self(), (vm_address_t) user_data, page_size);
    if (r != KERN_SUCCESS)
	printf("Call to vm_deallocate user_data failed %d\n", r);
    
    return r;
}	

/* mydriver_export:  Called by mydriver_server, which was created by MiG. */
kern_return_t mydriver_export
    (port_t server, out_user_data_t *user_data, unsigned int *length)
{
    kern_return_t r;
    port_t kernel_task = kern_serv_kernel_task_port();
    unsigned int tmp;
    
    if (!local_data)
    {
	// Get some vm for the mig out of band data to deallocate
	(void) vm_allocate
	    (task_self(), (vm_address_t *) user_data, page_size, TRUE);
	
	return KERN_FAILURE;
    }
    
    // Tack an ACK on the end of the imported data
    strcat(local_data, "ACK");
    *length = strlen(local_data) + 1;
    printf("\nData is: %s\n", local_data);

    //
    // Warning:  Loadable kernel servers run outside of the kernel task,
    // even though they use the kernel address map.
    //
    // This means that we have to load the task_self's user_data pointer from
    // the kernel's vm.  To do this we have to, counterintuitively again,
    // vm_read the local_data into our task's vm, NB we do not have to
    // previously allocate the vm.  The vm_read data will be deallocated
    // automatically by the mach message system as the type was declared
    // with dealloc on the mig type.
    //
    r = vm_read((vm_task_t) kernel_task, (vm_address_t) local_data,
	    page_size, (pointer_t *) user_data, &tmp);
    if (r != KERN_SUCCESS)
    {
	// Get some vm for the mig out of band data to deallocate
	(void) vm_allocate
	    (task_self(), (vm_address_t *) user_data, page_size, TRUE);
	
	switch (r)
	{
	case KERN_INVALID_ARGUMENT:
		printf("vm_read: KERN_INVALID_ARGUMENT %d\n", r);	break;
	case KERN_NO_SPACE:
		printf("vm_read: KERN_NO_SPACE %d\n", r);		break;
	case KERN_PROTECTION_FAILURE:
		printf("vm_read: KERN_PROTECTION_FAILURE %d\n", r);	break;
	case KERN_INVALID_ADDRESS:
		printf("vm_read: KERN_INVALID_ADDRESS %d\n", r);	break;
	default: printf("Call to vm_read failed: %d\n", r);		break;
	}
    }

    //
    // No matter what path we take through this function we always have some
    // disposable vm in task_self's memory for dealloc-ing.
    //
    return r;
}

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.