/* 
//  cmkrnl.c
//
//  OpenVMS Alpha example of accessing the Process Control Block (PCB)
//  via the value left in register R4 for the user's routine by the 
//  sys$cmkrnl call.
//
//  OpenVMS Alpha only.  Requires CMKRNL privilege.
//
//  Errors in kernel-mode code can corrupt critical data structures, 
//  can cause process deletions, and can potentially crash the OpenVMS
//  operating system.
//
//  To build:
//
//    $ CC/DECC CMKRNL+SYS$LIBRARY:SYS$LIB_C.TLB/LIBRARY
//    $ LINK CMKRNL
//    $ RUN CMKRNL
*/
#include <ssdef.h>
#include <starlet.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <pcbdef.h>    /* from sys$library:sys$lib_c.tlb */

/* 
//  Please see the OpenVMS Alpha calling standard for details on 
//  argument passing and particularly around register usage.
*/
#pragma linkage cmkrnl_pcb_and_2args = ( parameters( r4, r16, r17 ) )
#pragma use_linkage cmkrnl_pcb_and_2args( KernelRoutine )

/*
//  The KernelRoutine routine executes in kernel mode, but does 
//  absolutely nothing useful.
*/
int KernelRoutine( PCB *Pcb, int *UsrArg1, int *UsrArg2)
  {
  return SS$_NORMAL;
  }
main()
  {
  int RetStat;
  int ArgList[3];
  int i = 0;

  printf("OpenVMS Alpha example of calling sys$cmkrnl\n");

  /*
  //  Build the routine argument list in an array -- the KernelRoutine
  //  call expects two arguments, necessitating an array containing the 
  //  count and the two arguments.  The use of the linkage to access the
  //  PCB makes it appear that there are actually three arguments to the
  //  KernelRoutine call, from the perspective of the calling routine this 
  //  is not strictly correct -- only two arguments are passed in.
  */
  ArgList[++i] = 1; 
  ArgList[++i] = 2;
  ArgList[0] = i;

  /*
  //  Now invoke the KernelRoutine in kernel mode...
  */
  RetStat = sys$cmkrnl( KernelRoutine, ArgList );

  return RetStat;
  }

