|  | /*
 * MEMRES.C; demonstrate use of memory-resident sections.
 * This program is purported to work on OpenVMS Alpha V7.1 and higher.
 *
 * To compile: $ CC/PREFIX=ALL MEMRES
 * To link:    $ LINK/SYSEXE MEMRES
 * To define:  $! MEMRES can be provided as a command by either:
 *             $ MEMRES :== $SYS$DISK:[]MEMRES.EXE ! (foreign command symbol)
 *             $! or (only one of these two commands is necessary):
 *             $ DEFINE/JOB DCL$PATH SYS$DISK:[]   ! (tell DCL where to find)
 * To run:     $ MEMRES <section-name> <size-in-bytes>
 *
 * To delete a section, specify <section-name>, but omit <size-in-bytes>.
 *
 * *** Please Note:
 *
 * If the second argument specifies any number of bytes other than an
 * exact multiple of the page size, it is interpreted as <size-in-pages>.
 * Yes, that is a hazardous arrangement, however convenient it may be.
 * Take care not to deplete the available free memory on your system.
 * If I had known of a system data cell containing the current amount
 * of free memory, I would have checked it against the amount requested.
 *
 * If a third argument of "mb" is specified, the second argument is
 * interpreted as <size-in-Megabytes>.
 */
#include <builtins.h>		/* Alpha built-in functions	*/
#include <c_asm.h>		/* in-line assembler		*/
#include <descrip.h>		/* string descriptors		*/
#include <hwrpbdef.h>		/* H/W restart parameter block	*/
#include <ints.h>		/* integer types		*/
#include <lib$routines.h>	/* RTL LIB routines		*/
#include <secdef.h>		/* section flags		*/
#include <ssdef.h>		/* SS$_ message codes		*/
#include <starlet.h>		/* system services		*/
#include <stdio.h>		/* standard I/O			*/
#include <stdlib.h>		/* standard library		*/
#include <string.h>		/* string routines		*/
#include <stsdef.h>		/* message code format		*/
#include <vadef.h>		/* virtual address format/flags	*/
typedef struct
{
  uint32 cnt;
  uint32 off;
} pccs_t;
typedef union
{
  uint64 all;
  pccs_t pcc;
} pccu_t;
#pragma extern_model save
#pragma extern_model relaxed_refdef shr
extern const HWRPB *BOO$GA_HWRPB;	/* pointer to restart parameter block */
extern const uint32 MMG$GL_MEMSIZE;	/* actual memory size in pages */
extern const uint64 MMG$GQ_PAGE_SIZE;	/* system page size in bytes */
extern const uint64 MMG$GQ_PTES_PER_PAGE; /* # of PTEs that fit on 1 PT page */
extern const uint32 EXE$GL_SYSTICK;	/* # of 100-ns units per clock tick */
extern volatile int64 EXE$GQ_SYSTIME;	/* current quadword system time */
#pragma extern_model restore
#define one_KB 1024uL
#define one_MB (one_KB * one_KB)
static const $DESCRIPTOR(default_gs_name,"tst-mem-res-sec");
static const uint32 create_gdzro_flags =
	SEC$M_DZRO | SEC$M_GBL | SEC$M_PERM |
	SEC$M_SYSGBL | SEC$M_MRES | SEC$M_WRT;
static const uint32 mgblsc_flags =
	SEC$M_EXPREG | SEC$M_GBL | SEC$M_NO_OVERMAP | SEC$M_SYSGBL | SEC$M_WRT;
static const int64 systime_units_per_second = 10000000L;
static const char *access_mode_name[4] =
	{ "kernel", "executive", "supervisor", "user" };
void show_pcc(pccu_t pcc_beg, pccu_t pcc_end)
{
  pccu_t pcc_dif;
  double cpu_cycle_time_seconds, cpu_seconds, cpu_systime_units;
  int64 bintim;
  struct dsc$descriptor_s ascdsc;
  char asctim[24];
/* determine the CPU cycle time in seconds */
  cpu_cycle_time_seconds = BOO$GA_HWRPB->hwrpb$iq_cycle_count_freq;
  cpu_cycle_time_seconds = 1.0 / cpu_cycle_time_seconds;
/* calculate the elapsed and CPU times in cycles */
  pcc_dif.pcc.cnt = pcc_end.pcc.cnt - pcc_beg.pcc.cnt;
  pcc_dif.pcc.off = pcc_end.pcc.off - pcc_beg.pcc.off;
  pcc_dif.pcc.off += pcc_dif.pcc.cnt;
/* calculate the CPU time in seconds */
  cpu_seconds = cpu_cycle_time_seconds * (double)pcc_dif.pcc.off;
/* calculate the approximate CPU time in systime units */
  cpu_systime_units = (cpu_seconds+0.005) * (double)systime_units_per_second;
  bintim = -cpu_systime_units;
/* get text representation of CPU time interval */
  ascdsc.dsc$w_length  = sizeof(asctim) - 1;
  ascdsc.dsc$b_dtype   = DSC$K_DTYPE_T;
  ascdsc.dsc$b_class   = DSC$K_CLASS_S;
  ascdsc.dsc$a_pointer = asctim;
  sys$asctim(&ascdsc.dsc$w_length, &ascdsc, &bintim, 0);
  asctim[ascdsc.dsc$w_length] = '\0';
/* display only the CPU time (elapsed seems error-prone on SMP systems) */
  printf(" __RPCC() difference, CPU: %s; %E sec (%u cyc).\n",
	asctim, cpu_seconds, pcc_dif.pcc.off);
}
void report_lkwset_failure(int failure, int64 failed_va, uint64 failed_length)
{
  struct dsc$descriptor_s msgdsc;
  char msg[256];
  printf("Failed VA %016LX; %Lu page%s; ",
	failed_va, failed_length / MMG$GQ_PAGE_SIZE,
	(((failed_length / MMG$GQ_PAGE_SIZE) == 1) ? " " : "s"));
  msgdsc.dsc$w_length  = sizeof(msg) - 1;
  msgdsc.dsc$b_dtype   = DSC$K_DTYPE_T;
  msgdsc.dsc$b_class   = DSC$K_CLASS_S;
  msgdsc.dsc$a_pointer = msg;
  sys$getmsg(failure, &msgdsc.dsc$w_length, &msgdsc, 2, 0);
  msg[msgdsc.dsc$w_length] = '\0';
  printf("%s\n", msg);
}
int lock_all_regions()
{
  int status, failure;
  int64 region_start_va_64, lkwset_start_va_64, return_va_64, failed_va;
  uint64 lkwset_length_64, return_length_64, failed_length, locked_length;
  uint32 lregsum;
  regsum regsum;
  if (sizeof(regsum) != VA$C_REGSUM_LENGTH)
  {
    printf("    sizeof(regsum) = %u.\n", sizeof(regsum));
    printf("VA$C_REGSUM_LENGTH = %u.\n", VA$C_REGSUM_LENGTH);
  }
  region_start_va_64 = -1L;
  while ((status = sys$get_region_info(VA$_NEXT_REGSUM_BY_VA, 0,
	region_start_va_64, 0, sizeof(regsum), ®sum, &lregsum)) & 1)
  {
    if (lregsum != sizeof(regsum))
    {
      printf("      lregsum  = %u.\n", lregsum);
      printf("sizeof(regsum) = %u.\n", sizeof(regsum));
    }
    printf("\nRegion ID: %Lu.\n", *((uint64*)regsum.va$q_region_id));
    if (regsum.va$v_descend)
      printf("  descending\n");
    if (regsum.va$v_p0_space)
      printf("  in P0 space\n");
    if (regsum.va$v_p1_space)
      printf("  in P1 space\n");
    if (regsum.va$v_permanent)
      printf("  permanent\n");
/*
    if (regsum.va$v_no_clone)
      printf("  no clone\n");
 */
    if (regsum.va$v_shared_pts)
      printf("  shared page tables\n");
    printf("Region protection; owner mode: %s; create mode: %s\n",
	access_mode_name[regsum.va$v_owner_mode],
	access_mode_name[regsum.va$v_create_mode]);
    printf("   Start VA %016LX\n", regsum.va$pq_start_va);
    printf("1st Free VA %016LX\n", regsum.va$pq_first_free_va);
    printf("Region Size %Lu bytes; %Lu page%s; %Lu MB\n",
		*((uint64*)regsum.va$q_region_size),
		*((uint64*)regsum.va$q_region_size) / MMG$GQ_PAGE_SIZE,
(((*((uint64*)regsum.va$q_region_size) / MMG$GQ_PAGE_SIZE) == 1) ? " " : "s"),
		*((uint64*)regsum.va$q_region_size) / one_MB);
    if (regsum.va$v_descend)
    {
      lkwset_start_va_64 = regsum.va$pq_first_free_va;
      lkwset_start_va_64 += MMG$GQ_PAGE_SIZE;
      lkwset_length_64 = regsum.va$pq_start_va;
      lkwset_length_64 += *((uint64*)regsum.va$q_region_size);
      lkwset_length_64 -= lkwset_start_va_64;
    }
    else
    {
      lkwset_start_va_64 = regsum.va$pq_start_va;
      lkwset_length_64 = regsum.va$pq_first_free_va - regsum.va$pq_start_va;
    }
    printf("LKWSET VA %016LX; %Lu bytes; %Lu page%s; %Lu MB\n",
		lkwset_start_va_64,
		lkwset_length_64,
		lkwset_length_64 / MMG$GQ_PAGE_SIZE,
		(((lkwset_length_64 / MMG$GQ_PAGE_SIZE) == 1) ? " " : "s"),
		lkwset_length_64 / one_MB);
    failure = 0;
    failed_va = 0L;
    failed_length = 0uL;
    locked_length = 0uL;
    for (;;)
    {
      status = sys$lkwset_64(lkwset_start_va_64, lkwset_length_64, 0,
		&return_va_64, &return_length_64);
      if (return_va_64 == -1L)
      {
	return_length_64 = 0uL;
      }
      else
      {
	if (failed_length)
	{
	  report_lkwset_failure(failure, failed_va, failed_length);
	  failure = 0;
	  failed_va = 0L;
	  failed_length = 0uL;
	}
	printf("Locked VA %016LX; %Lu page%s into working set.\n",
		return_va_64, return_length_64 / MMG$GQ_PAGE_SIZE,
		(((return_length_64 / MMG$GQ_PAGE_SIZE) == 1) ? " " : "s"));
	lkwset_start_va_64 += return_length_64;
	lkwset_length_64   -= return_length_64;
	locked_length      += return_length_64;
      }
      if (!(status & 1))
      {
	if (failure == 0) failure = status;
	if (status != failure)
	{
	  report_lkwset_failure(failure, failed_va, failed_length);
	  failure = status;
	  failed_va = lkwset_start_va_64;
	  failed_length = 0uL;
	}
	else if (return_length_64)
	{
	  failed_va = lkwset_start_va_64;
	}
	lkwset_start_va_64 += MMG$GQ_PAGE_SIZE;
	lkwset_length_64   -= MMG$GQ_PAGE_SIZE;
	failed_length      += MMG$GQ_PAGE_SIZE;
      }
      if (status == SS$_LKWSETFUL) break;
      if (lkwset_length_64 == 0uL) break;
    } /* keep trying until done or lock limit reached */
    if (failed_length)
    {
      report_lkwset_failure(failure, failed_va, failed_length);
      failure = 0;
      failed_va = 0L;
      failed_length = 0uL;
    }
    printf("Total of %Lu bytes; %Lu page%s; %Lu MB locked in region ID %Lu.\n",
		locked_length,
		locked_length / MMG$GQ_PAGE_SIZE,
		(((locked_length / MMG$GQ_PAGE_SIZE) == 1) ? " " : "s"),
		locked_length / one_MB,
		*((uint64*)regsum.va$q_region_id));
    region_start_va_64 = regsum.va$pq_start_va;
    region_start_va_64 += *((uint64*)regsum.va$q_region_size);
  }
  return status;
}
int memres(int argc, char *argv[])
#pragma nostandard
main_program
#pragma standard
{
  int status;
  int msgvec[2] = {1,0};
  int64 systime_units_per_clock_int;
  int64 d64;
  uint64 i64, n64, i64prv, i64dsp;
  uint64 nbytes, nclkint, kclkint;
  uint64 clear_length;
  uint64 region_id;
  uint64 region_length;
  uint64 mapped_length;
  uint64 unmapped_length;
  uint64 deleted_length;
  uint64 reserved_length;
  struct dsc$descriptor_s gs_name;
  register pccu_t pcc_beg, pcc_end;
#pragma required_pointer_size save
#pragma required_pointer_size long
  void *region_va;
  void *mapped_va;
  void *unmapped_va;
  void *deleted_va;
  int64 *p64;
  void *_memset64(void *__s, int __c, size_t __n);
#pragma required_pointer_size restore
/* determine the expected system time increment for each clock interrupt */
  systime_units_per_clock_int = systime_units_per_second;
  systime_units_per_clock_int <<= 12L; /* factor of 4096 */
  systime_units_per_clock_int /= BOO$GA_HWRPB->hwrpb$iq_clock_int_freq;
/* this *should* be the same as EXE$GL_SYSTICK */
  if (systime_units_per_clock_int != EXE$GL_SYSTICK)
  {
    printf("EXE$GL_SYSTICK = %u.\n", EXE$GL_SYSTICK);
    printf("expected value = %Ld.\n", systime_units_per_clock_int);
  }
/* determine the global section name */
  gs_name.dsc$b_dtype = DSC$K_DTYPE_T;
  gs_name.dsc$b_class = DSC$K_CLASS_S;
  if (argc < 2)
  {
    gs_name.dsc$w_length  = default_gs_name.dsc$w_length;
    gs_name.dsc$a_pointer = default_gs_name.dsc$a_pointer;
  }
  else
  {
    gs_name.dsc$w_length  = strlen(argv[1]);
    gs_name.dsc$a_pointer = argv[1];
  }
/* determine the section size in bytes */
  nbytes = 0uL;
  if (argc > 2)
  {
    nbytes = atoq(argv[2]);
    if ((argc > 3) && !strcmp(argv[3],"mb"))
    {
      nbytes *= one_MB;
    }
    else if (nbytes % MMG$GQ_PAGE_SIZE)
    {
      printf("Section size (second argument)\n");
      printf("  is not an exact multiple of the page size (%Lu bytes);\n",
		MMG$GQ_PAGE_SIZE);
      printf("  interpreting value as %Lu pages,\n", nbytes);
      nbytes *= MMG$GQ_PAGE_SIZE;
      printf("  or %Lu bytes.\n", nbytes);
    }
    if (nbytes > (MMG$GQ_PAGE_SIZE*(MMG$GL_MEMSIZE/2)))
    {
      printf("You asked for more than half the memory on the system.\n");
      printf("This seems unreasonable, so you will get only one page.\n");
      nbytes = MMG$GQ_PAGE_SIZE;
    }
  }
/*
  printf("System memory size: %Lu bytes; %Lu pages; %Lu MB\n",
		MMG$GL_MEMSIZE * MMG$GQ_PAGE_SIZE,
		MMG$GL_MEMSIZE,
		MMG$GL_MEMSIZE * MMG$GQ_PAGE_SIZE / one_MB);
  printf("Page table entry size: %Lu bytes.\n",
		MMG$GQ_PAGE_SIZE / MMG$GQ_PTES_PER_PAGE);
  printf("Memory mapped by one PTE page: %Lu bytes; %Lu pages; %Lu MB\n",
		MMG$GQ_PAGE_SIZE * MMG$GQ_PTES_PER_PAGE,
		MMG$GQ_PTES_PER_PAGE,
		MMG$GQ_PAGE_SIZE * MMG$GQ_PTES_PER_PAGE / one_MB);
 */
/*
 * If section size in bytes is non-zero, try to create a new section.
 * If a section with the same name already exists, use that one.
 * Map the section into (64-bit) process virtual address space.
 * Create a special region so that shared page tables can be used.
 */
  if (nbytes)
  {
/* try to create a new section */
try_create_gdzro:
    reserved_length = 0uL;
    printf("Trying to create a new section \"%s\"...\n", gs_name.dsc$a_pointer);
    lib$init_timer(0);
    pcc_beg.all = __RPCC();
    status = sys$create_gdzro(
		&gs_name,			/* gs_name_64		*/
		0uL,				/* ident_64		*/
		0,				/* prot			*/
		nbytes,				/* length_64		*/
		0,				/* acmode		*/
		create_gdzro_flags,		/* flags		*/
		&reserved_length);		/* reserved_length_64	*/
    pcc_end.all = __RPCC();
    lib$show_timer(0);
    show_pcc(pcc_beg, pcc_end);
    msgvec[1] = status;
    sys$putmsg(msgvec,0,0,0);
    if (((status == SS$_MRES_PFNSMALL)
      || (status == SS$_INSFLPGS))
     && (reserved_length != 0uL)
     && (nbytes > reserved_length))
    {
      printf(
	"Trying again; reducing request from %Lu to reserved %Lu bytes.\n",
	nbytes, reserved_length);
      nbytes = reserved_length;
      goto try_create_gdzro;
    }
    else if (status == SS$_DUPLNAM)
    {
      printf("Section \"%s\" already exists;\n", gs_name.dsc$a_pointer);
    }
    else if (status & 1)
    {
      printf("New section \"%s\" created;\n", gs_name.dsc$a_pointer);
    }
    else
    {
      fprintf(stderr, "Failed to create section \"%s\".\n",
	gs_name.dsc$a_pointer);
      return status | STS$M_INHIB_MSG;
    }
    printf("  Reserved Length: %Lu bytes; %Lu pages; %Lu MB\n",
		reserved_length,
		reserved_length / MMG$GQ_PAGE_SIZE,
		reserved_length / one_MB);
/* create a region with suitable attributes */
    region_id = 0;
    region_va = 0;
    region_length = 0uL;
    printf("Trying to create a region for mapping the section...\n");
    lib$init_timer(0);
    pcc_beg.all = __RPCC();
    status = sys$create_region_64(
		nbytes,				/* length_64		*/
		VA$C_REGION_UCREATE_UOWN,	/* region_prot		*/
		VA$M_SHARED_PTS,		/* flags		*/
		®ion_id,			/* return_region_id_64	*/
		®ion_va,			/* return_va_64		*/
		®ion_length,			/* return_length_64	*/
		0uL);				/* start_va_64		*/
    pcc_end.all = __RPCC();
    lib$show_timer(0);
    show_pcc(pcc_beg, pcc_end);
    msgvec[1] = status;
    sys$putmsg(msgvec,0,0,0);
    if (!(status & 1))
    {
      fprintf(stderr, "Failed to create region for section.\n");
      return status | STS$M_INHIB_MSG;
    }
    printf("Created region ID %Lu for section;\n", region_id);
    printf("  Region VA %016LX; %Lu bytes; %Lu pages; %Lu MB\n",
		region_va,
		region_length,
		region_length / MMG$GQ_PAGE_SIZE,
		region_length / one_MB);
/* use the region to map the section */
    mapped_va = 0;
    mapped_length = 0uL;
    printf("Trying to map the section using the region...\n");
    lib$init_timer(0);
    pcc_beg.all = __RPCC();
    status = sys$mgblsc_64(
		&gs_name,			/* gs_name_64		*/
		0uL,				/* ident_64		*/
		®ion_id,			/* region_id_64		*/
		0uL,				/* section_offset_64	*/
		nbytes,				/* length_64		*/
		0,				/* acmode		*/
		mgblsc_flags,			/* flags		*/
		&mapped_va,			/* return_va_64		*/
		&mapped_length,			/* return_length_64	*/
		0uL);				/* start_va_64		*/
    pcc_end.all = __RPCC();
    lib$show_timer(0);
    show_pcc(pcc_beg, pcc_end);
    msgvec[1] = status;
    sys$putmsg(msgvec,0,0,0);
    if (!(status & 1))
    {
      fprintf(stderr, "Failed to map section.\n");
      return status | STS$M_INHIB_MSG;
    }
    printf("Mapped memory-resident section \"%s\";\n", gs_name.dsc$a_pointer);
    printf("  Mapped VA %016LX; %Lu bytes; %Lu pages; %Lu MB\n",
		mapped_va,
		mapped_length,
		mapped_length / MMG$GQ_PAGE_SIZE,
		mapped_length / one_MB);
/* try locking pages from all regions into working set (just for fun) */
    lock_all_regions();
/* describe the section as an array of signed quadword integers (time stamps) */
    n64 = mapped_length / sizeof(int64);
    p64 = mapped_va;
/* increment the mapping count in the lowest quadword */
    p64[0]++;
    i64 = p64[0];
    printf("This program has now mapped this section %Ld times.\n", i64);
/* clear any remaining section memory */
    clear_length = mapped_length - (sizeof(int64) * i64);
    if (clear_length < 0x100000000uL)
    {
      printf("Clearing %Lu section bytes...\n", clear_length);
      lib$init_timer(0);
      pcc_beg.all = __RPCC();
      _memset64(&p64[i64], 0, clear_length);
      pcc_end.all = __RPCC();
      lib$show_timer(0);
      show_pcc(pcc_beg, pcc_end);
    }
/* write some SYSTIME time stamps,
    printf("Writing %Lu quadword SYSTIME stamps...\n", n64-i64);
    lib$init_timer(0);
    pcc_beg.all = __RPCC();
    for (i64 = p64[0]; i64 < n64; i64++) p64[i64] = EXE$GQ_SYSTIME;
    pcc_end.all = __RPCC();
    lib$show_timer(0);
    show_pcc(pcc_beg, pcc_end);
/* look for and list changes in the time stamp values */
    nclkint = 0uL;
    i64prv = i64dsp = 1;
    for (i64 = 2; i64 < n64; i64++)
    {
      d64 = p64[i64] - p64[i64prv];
      if (d64)
      {
	kclkint = d64 / systime_units_per_clock_int;
	if (((kclkint < 0) ? -kclkint : kclkint) < 50)
	{
	  nclkint += kclkint;
	}
	else
	{
	  if (nclkint)
	  {
	    printf("(%Lu clock interrupts found in %Ld time stamps)\n",
		nclkint, i64-i64dsp);
	    nclkint = 0uL;
	  }
	  printf(
		"p64[%5Ld]: %+Ld.%07Lu seconds (%+Ld clock interrupts).\n",
		i64, d64 / systime_units_per_second,
		((d64 < 0L) ? -d64 : d64) % systime_units_per_second, kclkint);
	  i64dsp = i64;
	}
	i64prv = i64;
      }
    }
    if (nclkint)
    {
      printf("(%Lu clock interrupts found in %Ld time stamps)\n",
		nclkint, n64-i64dsp);
      nclkint = 0;
    }
/*
 * Delete the region (and any address space within it),  just to show
 * that it can be done.  Image rundown would have done this anyway.
 */
    printf("Trying to delete region ID %Lu...\n", region_id);
    lib$init_timer(0);
    pcc_beg.all = __RPCC();
    status = sys$delete_region_64(
		®ion_id,			/* region_id_64		*/
		0,				/* acmode		*/
		&deleted_va,			/* return_va_64		*/
		&deleted_length);		/* return_length_64	*/
    pcc_end.all = __RPCC();
    lib$show_timer(0);
    show_pcc(pcc_beg, pcc_end);
    msgvec[1] = status;
    sys$putmsg(msgvec,0,0,0);
    if (!(status & 1))
    {
      fprintf(stderr, "Failed to delete region ID %Lu.\n", region_id);
      return status | STS$M_INHIB_MSG;
    }
    printf("Deleted region ID %Lu.\n", region_id);
    printf(" Deleted VA %016LX; %Lu bytes; %Lu pages; %Lu MB\n",
		deleted_va,
		deleted_length,
		deleted_length / MMG$GQ_PAGE_SIZE,
		deleted_length / one_MB);
  }
/* section size is unspecified or zero; delete named system global section */
  else
  {
    printf("Trying to delete section \"%s\"...\n", gs_name.dsc$a_pointer);
    lib$init_timer(0);
    pcc_beg.all = __RPCC();
    status = sys$dgblsc(SEC$M_SYSGBL, &gs_name, 0);
    pcc_end.all = __RPCC();
    lib$show_timer(0);
    show_pcc(pcc_beg, pcc_end);
    msgvec[1] = status;
    sys$putmsg(msgvec,0,0,0);
    if (!(status & 1))
    {
      fprintf(stderr, "Failed to delete system global section \"%s\".\n",
	gs_name.dsc$a_pointer);
      return status | STS$M_INHIB_MSG;
    }
    printf("Deleted system global section \"%s\".\n", gs_name.dsc$a_pointer);
  }
  return status;
}
/*
 * The sequence of calls to (1) sys$create_gdzro, (2) sys$create_region_64,
 * (3) sys$mgblsc_64 (which was used above) could have been replaced by a
 * sequence of calls to (1) sys$create_region_64, (2) sys$crmpsc_gdzro_64.
 * The single sys$crmpsc_gdzro_64 service combines the actions of both the
 * sys$create_gdzro and sys$mgblsc_64 services.  The call would have looked
 * something like the following:
 */
/*
    mapped_va = 0;
    mapped_length = 0uL;
    reserved_length = 0uL;
    status = sys$crmpsc_gdzro_64(
		&gs_name,
		0uL,
		0,
		nbytes,
		®ion_id,
		0uL,
		0,
		create_gdzro_flags | mgblsc_flags,
		&mapped_va,
		&mapped_length,
		0uL,
		nbytes,
		&reserved_length);
 */
/*
 * The sys$deltva_64 service could have been used to unmap all or part
 * of the address space mapped to the section.  The call would have
 * looked something like the following:
 */
/*
    status = sys$deltva_64(
		®ion_id,
		mapped_va,
		mapped_length,
		0,
		&unmapped_va,
		&unmapped_length);
 */
 |