VMS rand: assign before check, not the other way around
[openssl.git] / crypto / rand / rand_vms.c
index daae926ef5be41ad6d3380079e993186ff7b8031..b263f94208b3dcb1b86646fa52e996254361c883 100644 (file)
@@ -46,70 +46,255 @@ typedef uint32_t *uint32_t__ptr32;
 #  pragma pointer_size restore
 # endif
 
-static const struct item_st {
+struct item_st {
     short length, code;         /* length is number of bytes */
-} item_data[] = {
-    {4,  JPI$_BUFIO},
-    {4,  JPI$_CPUTIM},
-    {4,  JPI$_DIRIO},
-    {4,  JPI$_IMAGECOUNT},
-    {8,  JPI$_LAST_LOGIN_I},
-    {8,  JPI$_LOGINTIM},
-    {4,  JPI$_PAGEFLTS},
-    {4,  JPI$_PID},
-    {4,  JPI$_PPGCNT},
-    {4,  JPI$_WSPEAK},
+};
+
+static const struct item_st DVI_item_data[] = {
+    {4,   DVI$_ERRCNT},
+    {4,   DVI$_REFCNT},
+};
+
+static const struct item_st JPI_item_data[] = {
+    {4,   JPI$_BUFIO},
+    {4,   JPI$_CPUTIM},
+    {4,   JPI$_DIRIO},
+    {4,   JPI$_IMAGECOUNT},
+    {4,   JPI$_PAGEFLTS},
+    {4,   JPI$_PID},
+    {4,   JPI$_PPGCNT},
+    {4,   JPI$_WSPEAK},
     /*
      * Note: the direct result is just a 32-bit address.  However, it points
      * to a list of 4 32-bit words, so we make extra space for them so we can
      * do in-place replacement of values
      */
-    {16, JPI$_FINALEXC},
+    {16,  JPI$_FINALEXC},
+};
+
+static const struct item_st JPI_item_data_64bit[] = {
+    {8,   JPI$_LAST_LOGIN_I},
+    {8,   JPI$_LOGINTIM},
+};
+
+static const struct item_st RMI_item_data[] = {
+    {4,   RMI$_COLPG},
+    {4,   RMI$_MWAIT},
+    {4,   RMI$_CEF},
+    {4,   RMI$_PFW},
+    {4,   RMI$_LEF},
+    {4,   RMI$_LEFO},
+    {4,   RMI$_HIB},
+    {4,   RMI$_HIBO},
+    {4,   RMI$_SUSP},
+    {4,   RMI$_SUSPO},
+    {4,   RMI$_FPG},
+    {4,   RMI$_COM},
+    {4,   RMI$_COMO},
+    {4,   RMI$_CUR},
+#if defined __alpha
+    {4,   RMI$_FRLIST},
+    {4,   RMI$_MODLIST},
+#endif
+    {4,   RMI$_FAULTS},
+    {4,   RMI$_PREADS},
+    {4,   RMI$_PWRITES},
+    {4,   RMI$_PWRITIO},
+    {4,   RMI$_PREADIO},
+    {4,   RMI$_GVALFLTS},
+    {4,   RMI$_WRTINPROG},
+    {4,   RMI$_FREFLTS},
+    {4,   RMI$_DZROFLTS},
+    {4,   RMI$_SYSFAULTS},
+    {4,   RMI$_ISWPCNT},
+    {4,   RMI$_DIRIO},
+    {4,   RMI$_BUFIO},
+    {4,   RMI$_MBREADS},
+    {4,   RMI$_MBWRITES},
+    {4,   RMI$_LOGNAM},
+    {4,   RMI$_FCPCALLS},
+    {4,   RMI$_FCPREAD},
+    {4,   RMI$_FCPWRITE},
+    {4,   RMI$_FCPCACHE},
+    {4,   RMI$_FCPCPU},
+    {4,   RMI$_FCPHIT},
+    {4,   RMI$_FCPSPLIT},
+    {4,   RMI$_FCPFAULT},
+    {4,   RMI$_ENQNEW},
+    {4,   RMI$_ENQCVT},
+    {4,   RMI$_DEQ},
+    {4,   RMI$_BLKAST},
+    {4,   RMI$_ENQWAIT},
+    {4,   RMI$_ENQNOTQD},
+    {4,   RMI$_DLCKSRCH},
+    {4,   RMI$_DLCKFND},
+    {4,   RMI$_NUMLOCKS},
+    {4,   RMI$_NUMRES},
+    {4,   RMI$_ARRLOCPK},
+    {4,   RMI$_DEPLOCPK},
+    {4,   RMI$_ARRTRAPK},
+    {4,   RMI$_TRCNGLOS},
+    {4,   RMI$_RCVBUFFL},
+    {4,   RMI$_ENQNEWLOC},
+    {4,   RMI$_ENQNEWIN},
+    {4,   RMI$_ENQNEWOUT},
+    {4,   RMI$_ENQCVTLOC},
+    {4,   RMI$_ENQCVTIN},
+    {4,   RMI$_ENQCVTOUT},
+    {4,   RMI$_DEQLOC},
+    {4,   RMI$_DEQIN},
+    {4,   RMI$_DEQOUT},
+    {4,   RMI$_BLKLOC},
+    {4,   RMI$_BLKIN},
+    {4,   RMI$_BLKOUT},
+    {4,   RMI$_DIRIN},
+    {4,   RMI$_DIROUT},
+    /* We currently get a fault when trying these.  TODO: To be figured out. */
+#if 0
+    {140, RMI$_MSCP_EVERYTHING},   /* 35 32-bit words */
+    {152, RMI$_DDTM_ALL},          /* 38 32-bit words */
+    {80,  RMI$_TMSCP_EVERYTHING}   /* 20 32-bit words */
+#endif
+    {4,   RMI$_LPZ_PAGCNT},
+    {4,   RMI$_LPZ_HITS},
+    {4,   RMI$_LPZ_MISSES},
+    {4,   RMI$_LPZ_EXPCNT},
+    {4,   RMI$_LPZ_ALLOCF},
+    {4,   RMI$_LPZ_ALLOC2},
+    {4,   RMI$_ACCESS},
+    {4,   RMI$_ALLOC},
+    {4,   RMI$_FCPCREATE},
+    {4,   RMI$_VOLWAIT},
+    {4,   RMI$_FCPTURN},
+    {4,   RMI$_FCPERASE},
+    {4,   RMI$_OPENS},
+    {4,   RMI$_FIDHIT},
+    {4,   RMI$_FIDMISS},
+    {4,   RMI$_FILHDR_HIT},
+    {4,   RMI$_DIRFCB_HIT},
+    {4,   RMI$_DIRFCB_MISS},
+    {4,   RMI$_DIRDATA_HIT},
+    {4,   RMI$_EXTHIT},
+    {4,   RMI$_EXTMISS},
+    {4,   RMI$_QUOHIT},
+    {4,   RMI$_QUOMISS},
+    {4,   RMI$_STORAGMAP_HIT},
+    {4,   RMI$_VOLLCK},
+    {4,   RMI$_SYNCHLCK},
+    {4,   RMI$_SYNCHWAIT},
+    {4,   RMI$_ACCLCK},
+    {4,   RMI$_XQPCACHEWAIT},
+    {4,   RMI$_DIRDATA_MISS},
+    {4,   RMI$_FILHDR_MISS},
+    {4,   RMI$_STORAGMAP_MISS},
+    {4,   RMI$_PROCCNTMAX},
+    {4,   RMI$_PROCBATCNT},
+    {4,   RMI$_PROCINTCNT},
+    {4,   RMI$_PROCNETCNT},
+    {4,   RMI$_PROCSWITCHCNT},
+    {4,   RMI$_PROCBALSETCNT},
+    {4,   RMI$_PROCLOADCNT},
+    {4,   RMI$_BADFLTS},
+    {4,   RMI$_EXEFAULTS},
+    {4,   RMI$_HDRINSWAPS},
+    {4,   RMI$_HDROUTSWAPS},
+    {4,   RMI$_IOPAGCNT},
+    {4,   RMI$_ISWPCNTPG},
+    {4,   RMI$_OSWPCNT},
+    {4,   RMI$_OSWPCNTPG},
+    {4,   RMI$_RDFAULTS},
+    {4,   RMI$_TRANSFLTS},
+    {4,   RMI$_WRTFAULTS},
+#if defined __alpha
+    {4,   RMI$_USERPAGES},
+#endif
+    {4,   RMI$_VMSPAGES},
+    {4,   RMI$_TTWRITES},
+    {4,   RMI$_BUFOBJPAG},
+    {4,   RMI$_BUFOBJPAGPEAK},
+    {4,   RMI$_BUFOBJPAGS01},
+    {4,   RMI$_BUFOBJPAGS2},
+    {4,   RMI$_BUFOBJPAGMAXS01},
+    {4,   RMI$_BUFOBJPAGMAXS2},
+    {4,   RMI$_BUFOBJPAGPEAKS01},
+    {4,   RMI$_BUFOBJPAGPEAKS2},
+    {4,   RMI$_BUFOBJPGLTMAXS01},
+    {4,   RMI$_BUFOBJPGLTMAXS2},
+    {4,   RMI$_DLCK_INCMPLT},
+    {4,   RMI$_DLCKMSGS_IN},
+    {4,   RMI$_DLCKMSGS_OUT},
+    {4,   RMI$_MCHKERRS},
+    {4,   RMI$_MEMERRS},
+};
+
+static const struct item_st RMI_item_data_64bit[] = {
+#if defined __ia64
+    {8,   RMI$_FRLIST},
+    {8,   RMI$_MODLIST},
+#endif
+    {8,   RMI$_LCKMGR_REQCNT},
+    {8,   RMI$_LCKMGR_REQTIME},
+    {8,   RMI$_LCKMGR_SPINCNT},
+    {8,   RMI$_LCKMGR_SPINTIME},
+    {8,   RMI$_CPUINTSTK},
+    {8,   RMI$_CPUMPSYNCH},
+    {8,   RMI$_CPUKERNEL},
+    {8,   RMI$_CPUEXEC},
+    {8,   RMI$_CPUSUPER},
+    {8,   RMI$_CPUUSER},
+#if defined __ia64
+    {8,   RMI$_USERPAGES},
+#endif
+    {8,   RMI$_TQETOTAL},
+    {8,   RMI$_TQESYSUB},
+    {8,   RMI$_TQEUSRTIMR},
+    {8,   RMI$_TQEUSRWAKE},
+};
+
+static const struct item_st SYI_item_data[] = {
+    {4,   SYI$_PAGEFILE_FREE},
 };
 
 /*
  * Input:
  * items_data           - an array of lengths and codes
- * items_data_num       - number of elements in that array, minus one
- *                        (caller MUST have space for one extra NULL element)
+ * items_data_num       - number of elements in that array
  *
  * Output:
  * items                - pre-allocated ILE3 array to be filled.
- *                        It's assume to have items_data_num elements.
+ *                        It's assumed to have items_data_num elements plus
+ *                        one extra for the terminating NULL element
  * databuffer           - pre-allocated 32-bit word array.
  *
- * Returns the number of bytes used in databuffer
+ * Returns the number of elements used in databuffer
  */
 static size_t prepare_item_list(const struct item_st *items_input,
                                 size_t items_input_num,
                                 ILE3 *items,
                                 uint32_t__ptr32 databuffer)
 {
-    const struct item_st *pitems_input;
-    ILE3 *pitems;
     size_t data_sz = 0;
 
-    for (pitems_input = items_input, pitems = items;
-         items_input_num-- > 0;
-         pitems_input++, pitems++) {
+    for (; items_input_num-- > 0; items_input++, items++) {
 
+        items->ile3$w_code = items_input->code;
         /* Special treatment of JPI$_FINALEXC */
-        if (pitems->ile3$w_code == JPI$_FINALEXC)
-            pitems->ile3$w_length = 4;
+        if (items->ile3$w_code == JPI$_FINALEXC)
+            items->ile3$w_length = 4;
         else
-            pitems->ile3$w_length = pitems_input->length;
+            items->ile3$w_length = items_input->length;
 
-        pitems->ile3$w_code   = pitems_input->code;
-        pitems->ile3$ps_bufaddr = databuffer;
-        pitems->ile3$ps_retlen_addr = 0;
+        items->ile3$ps_bufaddr = databuffer;
+        items->ile3$ps_retlen_addr = 0;
 
-        databuffer += pitems_input->length / sizeof(*databuffer);
-        data_sz += pitems_input->length;
+        databuffer += items_input->length / sizeof(databuffer[0]);
+        data_sz += items_input->length;
     }
     /* Terminating NULL entry */
-    pitems->ile3$w_length = pitems->ile3$w_code = 0;
+    items->ile3$w_length = items->ile3$w_code = 0;
+    items->ile3$ps_bufaddr = items->ile3$ps_retlen_addr = NULL;
 
-    return data_sz;
+    return data_sz / sizeof(databuffer[0]);
 }
 
 static void massage_JPI(ILE3 *items)
@@ -140,38 +325,121 @@ static void massage_JPI(ILE3 *items)
 /*
  * This number expresses how many bits of data contain 1 bit of entropy.
  *
- * For the moment, we assume about 0.5 entropy bits per data bit, or 1
- * bit of entropy per 2 data bits.
+ * For the moment, we assume about 0.05 entropy bits per data bit, or 1
+ * bit of entropy per 20 data bits.
  */
-#define ENTROPY_FACTOR  2
+#define ENTROPY_FACTOR  20
 
 size_t rand_pool_acquire_entropy(RAND_POOL *pool)
 {
-    ILE3 items[OSSL_NELEM(item_data) + 1];
-    /*
-     * All items get 1 or 2 32-bit words of data, except JPI$_FINALEXC
-     * We make sure that we have ample space
-     */
-    uint32_t data_buffer[(OSSL_NELEM(item_data)) * 2 + 4];
+    ILE3 JPI_items_64bit[OSSL_NELEM(JPI_item_data_64bit) + 1];
+    ILE3 RMI_items_64bit[OSSL_NELEM(RMI_item_data_64bit) + 1];
+    ILE3 DVI_items[OSSL_NELEM(DVI_item_data) + 1];
+    ILE3 JPI_items[OSSL_NELEM(JPI_item_data) + 1];
+    ILE3 RMI_items[OSSL_NELEM(RMI_item_data) + 1];
+    ILE3 SYI_items[OSSL_NELEM(SYI_item_data) + 1];
+    union {
+        /* This ensures buffer starts at 64 bit boundary */
+        uint64_t dummy;
+        uint32_t buffer[OSSL_NELEM(JPI_item_data_64bit) * 2
+                        + OSSL_NELEM(RMI_item_data_64bit) * 2
+                        + OSSL_NELEM(DVI_item_data)
+                        + OSSL_NELEM(JPI_item_data)
+                        + OSSL_NELEM(RMI_item_data)
+                        + OSSL_NELEM(SYI_item_data)
+                        + 4 /* For JPI$_FINALEXC */];
+    } data;
+    size_t total_elems = 0;
     size_t total_length = 0;
     size_t bytes_needed = rand_pool_bytes_needed(pool, ENTROPY_FACTOR);
     size_t bytes_remaining = rand_pool_bytes_remaining(pool);
 
-    total_length += prepare_item_list(item_data, OSSL_NELEM(item_data),
-                                      items, &data_buffer[total_length]);
+    /* Take all the 64-bit items first, to ensure proper alignment of data */
+    total_elems +=
+        prepare_item_list(JPI_item_data_64bit, OSSL_NELEM(JPI_item_data_64bit),
+                          JPI_items_64bit, &data.buffer[total_elems]);
+    total_elems +=
+        prepare_item_list(RMI_item_data_64bit, OSSL_NELEM(RMI_item_data_64bit),
+                          RMI_items_64bit, &data.buffer[total_elems]);
+    /* Now the 32-bit items */
+    total_elems += prepare_item_list(DVI_item_data, OSSL_NELEM(DVI_item_data),
+                                     DVI_items, &data.buffer[total_elems]);
+    total_elems += prepare_item_list(JPI_item_data, OSSL_NELEM(JPI_item_data),
+                                     JPI_items, &data.buffer[total_elems]);
+    total_elems += prepare_item_list(RMI_item_data, OSSL_NELEM(RMI_item_data),
+                                     RMI_items, &data.buffer[total_elems]);
+    total_elems += prepare_item_list(SYI_item_data, OSSL_NELEM(SYI_item_data),
+                                     SYI_items, &data.buffer[total_elems]);
+    total_length = total_elems * sizeof(data.buffer[0]);
 
-    /* Fill data_buffer with various info bits from this process */
+    /* Fill data.buffer with various info bits from this process */
     {
         uint32_t status;
+        uint32_t efn;
+        IOSB iosb;
+        $DESCRIPTOR(SYSDEVICE,"SYS$SYSDEVICE:");
 
-        if ((status = sys$getjpiw(EFN$C_ENF, 0, 0, items, 0, 0, 0))
+        if ((status = sys$getdviw(EFN$C_ENF, 0, &SYSDEVICE, DVI_items,
+                                  0, 0, 0, 0, 0)) != SS$_NORMAL) {
+            lib$signal(status);
+            return 0;
+        }
+        if ((status = sys$getjpiw(EFN$C_ENF, 0, 0, JPI_items_64bit, 0, 0, 0))
+            != SS$_NORMAL) {
+            lib$signal(status);
+            return 0;
+        }
+        if ((status = sys$getjpiw(EFN$C_ENF, 0, 0, JPI_items, 0, 0, 0))
+            != SS$_NORMAL) {
+            lib$signal(status);
+            return 0;
+        }
+        if ((status = sys$getsyiw(EFN$C_ENF, 0, 0, SYI_items, 0, 0, 0))
+            != SS$_NORMAL) {
+            lib$signal(status);
+            return 0;
+        }
+        /*
+         * The RMI service is a bit special, as there is no synchronous
+         * variant, so we MUST create an event flag to synchronise on.
+         */
+        if ((status = lib$get_ef(&efn)) != SS$_NORMAL) {
+            lib$signal(status);
+            return 0;
+        }
+        if ((status = sys$getrmi(efn, 0, 0, RMI_items_64bit, &iosb, 0, 0))
             != SS$_NORMAL) {
             lib$signal(status);
             return 0;
         }
+        if ((status = sys$synch(efn, &iosb)) != SS$_NORMAL) {
+            lib$signal(status);
+            return 0;
+        }
+        if (iosb.iosb$l_getxxi_status != SS$_NORMAL) {
+            lib$signal(iosb.iosb$l_getxxi_status);
+            return 0;
+        }
+        if ((status = sys$getrmi(efn, 0, 0, RMI_items, &iosb, 0, 0))
+            != SS$_NORMAL) {
+            lib$signal(status);
+            return 0;
+        }
+        if ((status = sys$synch(efn, &iosb)) != SS$_NORMAL) {
+            lib$signal(status);
+            return 0;
+        }
+        if (iosb.iosb$l_getxxi_status != SS$_NORMAL) {
+            lib$signal(iosb.iosb$l_getxxi_status);
+            return 0;
+        }
+        if ((status = lib$free_ef(&efn)) != SS$_NORMAL) {
+            lib$signal(status);
+            return 0;
+        }
     }
 
-    massage_JPI(items);
+    massage_JPI(JPI_items);
 
     /*
      * If we can't feed the requirements from the caller, we're in deep trouble.
@@ -196,8 +464,8 @@ size_t rand_pool_acquire_entropy(RAND_POOL *pool)
         total_length = bytes_remaining;
 
     /* We give the pessimistic value for the amount of entropy */
-    rand_pool_add(pool, (unsigned char *)data_buffer, total_length,
-                  total_length / ENTROPY_FACTOR);
+    rand_pool_add(pool, (unsigned char *)data.buffer, total_length,
+                  8 * total_length / ENTROPY_FACTOR);
     return rand_pool_entropy_available(pool);
 }