HP OpenVMS Systems Documentation

Content starts here

OpenVMS Programming Concepts Manual


Previous Contents Index


Appendix A
C Macros for 64-Bit Addressing

This appendix describes the following C macros for manipulating 64-bit addresses, for checking the sign extension of the low 32 bits of 64-bit values, and for checking descriptors for the 64-bit format:

  • $DESCRIPTOR64
  • $is_desc64
  • $is_32bits

DESCRIPTOR64

Constructs a 64-bit string descriptor.

Format

$DESCRIPTOR64 name, string


Description

name is name of variable
string is address of string

Example:



        int status;
        $DESCRIPTOR64 (gblsec, "GBLSEC_NAME");

        ...

        /* Create global page file section */
        status = sys$create_gpfile (&gblsec, 0, 0, section_size, 0, 0);

        ...

This macro resides in descrip.h in SYS$LIBRARY:DECC$RTLDEF.TLB.


$is_desc64

Distinguishes a 64-bit descriptor.

Format

$is_desc64 desc


Description

desc is address of 32-bit or 64-bit descriptor

Returns:

0 if descriptor is 32-bit descriptor
1 if descriptor is 64-bit descriptor

Example:


#include <descrip.h>
#include <far_pointers.h>
...
        if ($is_desc64 (user_desc))
        {
                /* Get 64-bit address and 64-bit length from descriptor */
                ...
        }
        else
        {
               /* Get 32-bit address and 16-bit length from descriptor */
               ...
        }

This macro resides in descrip.h in SYS$LIBRARY:DECC$RTLDEF.TLB.


$is_32bits

Tests if a quadword is 32-bit sign-extended.

Format

$is_32bits arg


Description

Input: arg is 64-bit value

Output:

1 if arg is 32-bit sign-extended
0 if arg is not 32-bit sign-extended

Example:


        #include <starlet_bigpage.h>
        ...
        if ($is_32bits(user_va))
                counter_32++;   /* Count number of 32-bit references */
        else
                counter_64++;  /* Count number of 64-bit references */

This macro resides in starlet_bigpage.h in SYS$LIBRARY:SYS$STARLET_C.TLB.


Appendix B
64-Bit Example Program

This example program demonstrates the 64-bit region creation and deletion system services. It uses SYS$CREATE_REGION_64 to create a region and then uses SYS$EXPREG_64 to allocate virtual addresses within that region. The virtual address space and the region are deleted by calling SYS$DELETE_REGION_64.


/*
    This program creates a region in P2 space using the region creation
    service and then creates VAs within that region.  The intent is to
    demonstrate the use of the region services and how to allocate virtual
    addresses within a region.  The program also makes use of 64-bit
    descriptors and uses them to format return values into messages with the
    aid of SYS$GETMSG.

    To build and run this program type:

    $ CC/POINTER_SIZE=32/STANDARD=RELAXED/DEFINE=(__NEW_STARLET=1) -
        REGIONS.C
    $ LINK REGIONS.OBJ
    $ RUN REGIONS.EXE
*/

#include    <descrip.h>             /* Descriptor Definitions               */
#include    <far_pointers.h>        /* Long Pointer Definitions             */
#include    <gen64def.h>            /* Generic 64-bit Data Type Definition  */
#include    <iledef.h>              /* Item List Entry Definitions          */
#include    <ints.h>                /* Various Integer Typedefs             */
#include    <iosbdef.h>             /* I/O Status Block Definition          */
#include    <psldef.h>              /* PSL$ Constants                       */
#include    <ssdef.h>               /* SS$_ Message Codes                   */
#include    <starlet.h>             /* System Service Prototypes            */
#include    <stdio.h>               /* printf                               */
#include    <stdlib.h>              /* malloc, free                         */
#include    <string.h>              /* memset                               */
#include    <syidef.h>              /* $GETSYI Item Code Definitions        */
#include    <vadef.h>               /* VA Creation Flags and Constants      */


/*  Module-wide constants and macros.                                       */

#define     BUFFER_SIZE         132
#define     HW_NAME_LENGTH       32
#define     PAGELET_SIZE        512
#define     REGION_SIZE         128

#define     good_status(code)   ((code) & 1)


/*  Module-wide Variables                                                   */

int
    page_size;

$DESCRIPTOR64 (msgdsc, "");


/*  Function Prototypes                                                    */

int get_page_size (void);
static void print_message (int code, char *string);

main (int argc, char **argv)
{
    int
        i,
        status;

    uint64
        length_64,
        master_length_64,
        return_length_64;

    GENERIC_64
        region_id_64;

    VOID_PQ
        master_va_64,
        return_va_64;


/*  Get system page size, using SYS$GETSYI.                                 */

    status = get_page_size ();
    if (!good_status (status))
        return (status);


/*  Get a buffer for the message descriptor.                                */

    msgdsc.dsc64$pq_pointer = malloc (BUFFER_SIZE);
    printf ("Message Buffer Address = %016LX\n\n", msgdsc.dsc64$pq_pointer);


/*  Create a region in P2 space.                                            */

    length_64 = REGION_SIZE*page_size;
    status = sys$create_region_64 (
        length_64,                  /* Size of Region to Create             */
        VA$C_REGION_UCREATE_UOWN,   /* Protection on Region                 */
        0,                          /* Allocate in Region to Higher VAs     */
        &region_id_64,              /* Region ID                            */
        &master_va_64,              /* Starting VA in Region Created        */
        &master_length_64);         /* Size of Region Created               */
    if (!good_status (status))
    {
        print_message (status, "SYS$CREATE_REGION_64");
        return (status);
    }

    printf ("\nSYS$CREATE_REGION_64 Created this Region:  %016LX - %016LX\n",
        master_va_64,
        (uint64) master_va_64 + master_length_64 - 1);


/*  Create virtual address space within the region.                         */

    for (i = 0; i < 3; ++i)
    {
        status = sys$expreg_64 (
            &region_id_64,      /* Region to Create VAs In                  */
            page_size,          /* Number of Bytes to Create                */
            PSL$C_USER,         /* Access Mode                              */
            0,                  /* Creation Flags                           */
            &return_va_64,      /* Starting VA in Range Created             */
            &return_length_64); /* Number of Bytes Created                  */
        if (!good_status (status))
        {
            print_message (status, "SYS$EXPREG_64");
            return status;
        }
        printf ("Filling %016LX - %16LX with %0ds.\n",
            return_va_64,
            (uint64) return_va_64 + return_length_64 - 1,
            i);
        memset (return_va_64, i, page_size);
    }


/*  Return the virtual addresses created within the region, as well as the
    region itself.                                                          */

    printf ("\nReturning Master Region:  %016LX - %016LX\n",
        master_va_64,
        (uint64) master_va_64 + master_length_64 - 1);

    status = sys$delete_region_64 (
        &region_id_64,      /* Region to Delete                             */
        PSL$C_USER,         /* Access Mode                                  */
        &return_va_64,      /* VA Deleted                                   */
        &return_length_64); /* Length Deleted                               */

    if (good_status (status))
        printf ("SYS$DELETE_REGION_64 Deleted VAs Between:  %016LX - %016LX\n",
            return_va_64,
            (uint64) return_va_64 + return_length_64 - 1);
    else
    {
        print_message (status, "SYS$DELTE_REGION_64");
        return (status);
    }

/*  Return message buffer.                                                  */

    free (msgdsc.dsc64$pq_pointer);
}


/*  This routine obtains the system page size using SYS$GETSYI.  The return
    value is recorded in the module-wide location, page_size.               */

int get_page_size ()
{
int
    status;

IOSB
    iosb;

ILE3
    item_list [2];


/* Fill in SYI item list to retrieve the system page size.                  */

    item_list[0].ile3$w_length       = sizeof (int);
    item_list[0].ile3$w_code         = SYI$_PAGE_SIZE;
    item_list[0].ile3$ps_bufaddr     = &page_size;
    item_list[0].ile3$ps_retlen_addr = 0;
    item_list[1].ile3$w_length       = 0;
    item_list[1].ile3$w_code         = 0;


/* Get the system page size.                                                */

    status = sys$getsyiw (
                0,                              /* EFN                      */
                0,                              /* CSI address              */
                0,                              /* Node name                */
                &item_list,                     /* Item list                */
                &iosb,                          /* I/O status block         */
                0,                              /* AST address              */
                0);                             /* AST parameter            */

    if (!good_status (status))
    {
        print_message (status, "SYS$GETJPIW");
        return (status);
    }
    if (!good_status (iosb.iosb$w_status))
    {
        print_message (iosb.iosb$w_status, "SYS$GETJPIW IOSB");
        return (iosb.iosb$w_status);
    }

    return SS$_NORMAL;
}


/*  This routine takes the message code passed to the routine and then uses
    SYS$GETMSG to obtain the associated message text.  That message is then
    printed to stdio along with a user-supplied text string.                */

#pragma inline (print_message)
static void print_message (int code, char *string)
{
    msgdsc.dsc64$q_length = BUFFER_SIZE;
    sys$getmsg (
        code,                                       /* Message Code         */
        (unsigned short *) &msgdsc.dsc64$q_length,  /* Returned Length      */
        &msgdsc,                                    /* Message Descriptor   */
        15,                                         /* Message Flags        */
        0);                                         /* Optional Parameter   */
    *(msgdsc.dsc64$pq_pointer+msgdsc.dsc64$q_length) = '\0';
     printf ("Call to %s returned:  %s\n",
        string,
        msgdsc.dsc64$pq_pointer);
}


Appendix C
VLM Example Program

This example program demonstrates the memory management VLM features described in Chapter 16.



/*
    This program creates and maps to a memory-resident global section using
    shared page tables.  The program requires a reserved memory entry
    (named In_Memory_Database) in the Reserved Memory Registry.

    The entry in the registry is created using SYSMAN as follows:

    $ MCR SYSMAN
    SYSMAN> RESERVED_MEMORY ADD "In_Memory_Database"/ALLOCATE/PAGE_TABLES -
        /ZERO/SIZE=64/GROUP=100

    The above command creates an entry named In_Memory_Database that is
    64M bytes in size and requests that the physical memory be allocated
    during system initialization.  This enables the physical memory to
    be mapped with granularity hints by the SYS$CRMPSC_GDZRO_64 system
    service.  It also requests that physical memory be allocated for
    page tables for the named entry, requests the allocated memory be
    zeroed, and requests that UIC group number 100 be associated with
    the entry.


    Once the entry has been created with SYSMAN, the system must be
    re-tuned with AUTOGEN.  Doing so allows AUTOGEN to re-calculate
    values for SYSGEN parameters that are sensitive to changes in
    physical memory sizes.  (Recall that the Reserved Memory Registry
    takes physical pages away from the system.)  Once AUTOGEN has
    been run, the system must be rebooted.


    Use the following commands to compile and link this program:

    $ CC/POINTER_SIZE=32 shared_page_tables_example
    $ LINK shared_page_tables_example

    Since 64-bit virtual addresses are used by this program, a Version
    5.2 Compaq C compiler or later is required to compile it.
*/
#define     __NEW_STARLET   1

#include    <DESCRIP>
#include    <FAR_POINTERS>
#include    <GEN64DEF>
#include    <INTS>
#include    <PSLDEF>
#include    <SECDEF>
#include    <SSDEF>
#include    <STARLET>
#include    <STDIO>
#include    <STDLIB>
#include    <STRING>
#include    <VADEF>

#define     bad_status(status) (((status) & 1) != 1)
#define     ONE_MEGABYTE    0x100000


main ()
{
    int
        status;

    $DESCRIPTOR (section_name, "In_Memory_Database");

    uint32
        region_flags = VA$M_SHARED_PTS,   /* Shared PT region. */
        section_flags = SEC$M_EXPREG;

    uint64
        mapped_length,
        requested_size = 64*ONE_MEGABYTE,
        section_length = 64*ONE_MEGABYTE,
        region_length;

    GENERIC_64
        region_id;

    VOID_PQ
        mapped_va,
        region_start_va;


    printf ("Shared Page Table Region Creation Attempt:  Size = %0Ld\n",
        requested_size);


/*  Create a shared page table region. */

    status = sys$create_region_64 (
        requested_size,                 /* Size in bytes of region */
        VA$C_REGION_UCREATE_UOWN,       /* Region VA creation and owner mode */
        region_flags,                   /* Region Flags:  shared page tables */
        &region_id,                     /* Region ID */
        &region_start_va,               /* Starting VA for region */
        &region_length);                /* Size of created region */

    if (bad_status (status))
    {
        printf ("ERROR:  Unable to create region of size %16Ld\n\n",
            requested_size);
        return;
    }

    printf ("Shared Page Table Region Created:  VA = %016LX, Size = %0Ld\n\n",
        region_start_va,
        region_length);


/* Create and map a memory-resident section with shared page tables
       into the shared page table region. */

    printf ("Create and map to section %s\n", section_name.dsc$a_pointer);
    status = sys$crmpsc_gdzro_64 (
            &section_name,              /* Section name */
            0,                          /* Section Ident */
            0,                          /* Section protection */
            section_length,             /* Length of Section */
            &region_id,                 /* RDE */
            0,                          /* Section Offset; map entire section */
            PSL$C_USER,                 /* Access Mode */
            section_flags,              /* Section Creation Flags */
            &mapped_va,                 /* Return VA */
            &mapped_length);            /* Return Mapped Length */

    if (bad_status (status))
        printf ("ERROR:  Unable to Create and Map Section %s, status = %08x\n\n",
                section_name.dsc$a_pointer,
                status);
    else
    {
        printf ("Section %s created, Section Length = %0Ld\n",
                section_name.dsc$a_pointer,
                section_length);
        printf ("    Mapped VA = %016LX, Mapped Length = %0Ld\n\n",
                mapped_va,
                mapped_length);
    }

    /* Delete the shared page table.  This will cause the mapping to the
       section and the section itself to be deleted. */

    printf ("Delete the mapping to the memory-resident global section");
    printf (" and the shared\n    page table region.\n");
    status = sys$delete_region_64 (
            &region_id,
            PSL$C_USER,
            &region_start_va,
            &region_length);

    if (bad_status (status))
        printf ("ERROR:  Unable to delete shared page table region, status = %08x\n\n", status);
    else
        printf ("Region Deleted, Start VA = %016LX, Length = %016LX\n\n",
                region_start_va,
                region_length);
    printf ("\n");
}

This example program displays the following output:


Shared Page Table Region Creation Attempt:  Size = 67108864
Shared Page Table Region Created:  VA = FFFFFFFBFC000000, Size = 67108864

Create and map to section In_Memory_Database
Section In_Memory_Database created, Section Length = 67108864
    Mapped VA = FFFFFFFBFC000000, Mapped Length = 67108864

Delete the mapping to the memory-resident global section and the shared
    page table region.
Region Deleted, Start VA = FFFFFFFBFC000000, Length = 0000000004000000


Appendix D
Generic Macros for Calling System Services

This appendix describes the use of generic macros to specify argument lists with appropriate symbols and conventions in the system services interface to MACRO assemblers.

System service macros generate argument lists and CALL instructions to call system services. These macros are located in the system library SYS$LIBRARY:STARLET.MLB. When you assemble a source program, this library is searched automatically for unresolved references.

Knowledge of VAX MACRO rules for assembly language programming is required for understanding the material presented in this appendix. The VAX MACRO and Instruction Set Reference Manual contains the necessary prerequisite information.

Each system service has four macros associated with it. These macros allow you to define symbolic names for argument offsets, construct argument lists for system services, and call system services. Table D-1 lists the generic macros and the functions they serve.

Table D-1 Generic Argument List Macros of the System Service Interface
Macro Function
$ nameDEF Defines symbolic names for the argument list offsets
$ name Defines symbolic names for the argument list offsets and constructs the argument list
$ name_S Calls the system service and constructs the argument list
$ name_G Calls the system service and uses the argument list constructed by $ name macro

D.1 Using Macros to Construct Argument Lists

You can use two generic macros for constructing argument lists for system services:
$name
$name_S

The macro you use depends on which macro you are going to use to call the system service. If you use the $name_G macro to call a system service, you should use the $name macro to construct the argument list. If you use the $name_S macro to call a system service, you can also use it to construct the argument list.

D.1.1 Specifying Arguments with the $name_S Macro and the $name Macro

When you use the $name_S or the $name macro to construct an argument list for a system service, you can specify arguments in any one of three ways:

  • By using keywords to describe the arguments. All keywords must be followed by an equals sign (=) and then by the value of the argument.
  • By using positional order, with omitted arguments indicated by commas in the argument positions. You can omit commas for optional trailing arguments.
  • By using both positional order and keyword names (positional arguments must be listed first).

For example, $MYSERVICE can have the following format:


$MYSERVICE arga ,[argb] ,[argc] ,argd

For purposes of this example, assume that arga and argb require you to specify numeric values and that argc and argd require you to specify addresses.

Examples D-1 and D-2 show valid ways of writing the $name_S macro to call $MYSERVICE.

Example D-1 Using Keywords with the$ name_S Macro

MYARGD: .LONG   100
          .
          .
          .
        $MYSERVICE_S ARGB=#0,ARGC=0,ARGA=#1,ARGD=MYARGD

Example D-2 Specifying Arguments in Positional Order with the$ name_S Macro

MYARGD: .LONG   100
          .
          .
          .
        $MYSERVICE_S #1,,,MYARGD

The argument list is pushed on the stack, as follows:


     PUSHAL     MYARGD
     PUSHL      #0
     PUSHL      #0
     PUSHL      #1

Note that all arguments, whether specified positionally or with keywords, must be valid assembler expressions because they are used as source operands in instructions.

Examples D-3 and D-4 show valid ways of writing a $name macro to construct an argument list for a later call to $MYSERVICE.

Example D-3 Using Keywords with the$ name Macro

LIST:   $MYSERVICE -
                ARGB=0, -
                ARGC=0, -
                ARGA=1, -
                ARGD=MYARGD

Example D-4 Specifying Arguments in Positional Order with the$ name Macro

LIST:   $MYSERVICE -
                1,,,MYARGD

Both methods generate the following:


LIST:   .LONG   4
        .LONG   1
        .LONG   0
        .LONG   0
        .ADDRESS -
                MYARGD

Note that all arguments, whether specified positionally or by keyword, must be expressions that the assembler can evaluate to generate .LONG or .ADDRESS data directives. Contrast this to the arguments for the $name_S macro, which must be valid assembler expressions because they are used as source operands in instructions.


Previous Next Contents Index