diff --git a/ChangeLog b/ChangeLog
index cf2c882b7..75a2867a8 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -14,6 +14,18 @@ Security
 
 Features
    * Allow comments in test data files.
+   * The selftest program can execute a subset of the tests based on command
+     line arguments.
+   * New unit tests for timing. Improve the self-test to be more robust
+     when run on a heavily-loaded machine.
+   * Add alternative implementation support for CCM and CMAC (MBEDTLS_CCM_ALT,
+     MBEDTLS_CMAC_ALT). Submitted by Steve Cooreman, Silicon Labs.
+   * Add support for alternative implementations of GCM, selected by the
+     configuration flag MBEDTLS_GCM_ALT.
+
+New deprecations
+   * Deprecate usage of RSA primitives with non-matching key-type
+     (e.g., signing with a public key).
 
 API Changes
    * Extend RSA interface by multiple functions allowing structure-
@@ -73,6 +85,10 @@ Bugfix
    * Fix incorrect unit in benchmark output. #850
    * Fix crash when calling mbedtls_ssl_cache_free() twice. Found by
      MilenkoMitrovic, #1104
+   * Fix mbedtls_timing_alarm(0) on Unix.
+   * Fix use of uninitialized memory in mbedtls_timing_get_timer when reset=1.
+   * Fix possible memory leaks in mbedtls_gcm_self_test().
+   * Added missing return code checks in mbedtls_aes_self_test().
 
 Changes
    * Extend cert_write example program by options to set the CRT version
@@ -82,6 +98,7 @@ Changes
      particular, don't require P,Q if neither CRT nor blinding are
      used. Reported and fix proposed independently by satur9nine and sliai
      on GitHub.
+   * Only run AES-192 self-test if AES-192 is available. Fixes #963.
 
 = mbed TLS 2.6.0 branch released 2017-08-10
 
diff --git a/include/mbedtls/aes.h b/include/mbedtls/aes.h
index 1829f7240..c8dd0f355 100644
--- a/include/mbedtls/aes.h
+++ b/include/mbedtls/aes.h
@@ -36,9 +36,13 @@
 #define MBEDTLS_AES_ENCRYPT     1
 #define MBEDTLS_AES_DECRYPT     0
 
+/* Error codes in range 0x0020-0x0022 */
 #define MBEDTLS_ERR_AES_INVALID_KEY_LENGTH                -0x0020  /**< Invalid key length. */
 #define MBEDTLS_ERR_AES_INVALID_INPUT_LENGTH              -0x0022  /**< Invalid data input length. */
 
+/* Error codes in range 0x0023-0x0023 */
+#define MBEDTLS_ERR_AES_FEATURE_UNAVAILABLE               -0x0023  /**< Feature not available, e.g. unsupported AES key size. */
+
 #if ( defined(__ARMCC_VERSION) || defined(_MSC_VER) ) && \
     !defined(inline) && !defined(__cplusplus)
 #define inline __inline
diff --git a/include/mbedtls/ccm.h b/include/mbedtls/ccm.h
index ef75839ba..579402fd4 100644
--- a/include/mbedtls/ccm.h
+++ b/include/mbedtls/ccm.h
@@ -28,6 +28,10 @@
 #define MBEDTLS_ERR_CCM_BAD_INPUT      -0x000D /**< Bad input parameters to function. */
 #define MBEDTLS_ERR_CCM_AUTH_FAILED    -0x000F /**< Authenticated decryption failed. */
 
+#if !defined(MBEDTLS_CCM_ALT)
+// Regular implementation
+//
+
 #ifdef __cplusplus
 extern "C" {
 #endif
@@ -125,6 +129,18 @@ int mbedtls_ccm_auth_decrypt( mbedtls_ccm_context *ctx, size_t length,
                       const unsigned char *input, unsigned char *output,
                       const unsigned char *tag, size_t tag_len );
 
+#ifdef __cplusplus
+}
+#endif
+
+#else  /* !MBEDTLS_CCM_ALT */
+#include "ccm_alt.h"
+#endif /* !MBEDTLS_CCM_ALT */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
 #if defined(MBEDTLS_SELF_TEST) && defined(MBEDTLS_AES_C)
 /**
  * \brief          Checkup routine
diff --git a/include/mbedtls/cmac.h b/include/mbedtls/cmac.h
index 9a2b96bc9..4d3f2d2f4 100644
--- a/include/mbedtls/cmac.h
+++ b/include/mbedtls/cmac.h
@@ -39,6 +39,8 @@ extern "C" {
 #define MBEDTLS_CIPHER_BLKSIZE_MAX      8   /* longest used by CMAC is 3DES */
 #endif
 
+#if !defined(MBEDTLS_CMAC_ALT)
+
 /**
  * CMAC context structure - Contains internal state information only
  */
@@ -154,6 +156,18 @@ int mbedtls_aes_cmac_prf_128( const unsigned char *key, size_t key_len,
                               unsigned char output[16] );
 #endif /* MBEDTLS_AES_C */
 
+#ifdef __cplusplus
+}
+#endif
+
+#else  /* !MBEDTLS_CMAC_ALT */
+#include "cmac_alt.h"
+#endif /* !MBEDTLS_CMAC_ALT */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
 #if defined(MBEDTLS_SELF_TEST) && ( defined(MBEDTLS_AES_C) || defined(MBEDTLS_DES_C) )
 /**
  * \brief          Checkup routine
diff --git a/include/mbedtls/config.h b/include/mbedtls/config.h
index d878e0aac..5b2c4ada5 100644
--- a/include/mbedtls/config.h
+++ b/include/mbedtls/config.h
@@ -266,8 +266,11 @@
 //#define MBEDTLS_ARC4_ALT
 //#define MBEDTLS_BLOWFISH_ALT
 //#define MBEDTLS_CAMELLIA_ALT
+//#define MBEDTLS_CCM_ALT
+//#define MBEDTLS_CMAC_ALT
 //#define MBEDTLS_DES_ALT
 //#define MBEDTLS_RSA_ALT
+//#define MBEDTLS_GCM_ALT
 //#define MBEDTLS_XTEA_ALT
 //#define MBEDTLS_MD2_ALT
 //#define MBEDTLS_MD4_ALT
diff --git a/include/mbedtls/error.h b/include/mbedtls/error.h
index d51bcdec3..4eb7b78eb 100644
--- a/include/mbedtls/error.h
+++ b/include/mbedtls/error.h
@@ -52,7 +52,7 @@
  * GCM       2  0x0012-0x0014
  * BLOWFISH  2  0x0016-0x0018
  * THREADING 3  0x001A-0x001E
- * AES       2  0x0020-0x0022
+ * AES       2  0x0020-0x0022   0x0023-0x0023
  * CAMELLIA  2  0x0024-0x0026
  * XTEA      1  0x0028-0x0028
  * BASE64    2  0x002A-0x002C
diff --git a/include/mbedtls/gcm.h b/include/mbedtls/gcm.h
index 1b77aaedd..8f3b56575 100644
--- a/include/mbedtls/gcm.h
+++ b/include/mbedtls/gcm.h
@@ -33,6 +33,8 @@
 #define MBEDTLS_ERR_GCM_AUTH_FAILED                       -0x0012  /**< Authenticated decryption failed. */
 #define MBEDTLS_ERR_GCM_BAD_INPUT                         -0x0014  /**< Bad input parameters to function. */
 
+#if !defined(MBEDTLS_GCM_ALT)
+
 #ifdef __cplusplus
 extern "C" {
 #endif
@@ -206,6 +208,18 @@ int mbedtls_gcm_finish( mbedtls_gcm_context *ctx,
  */
 void mbedtls_gcm_free( mbedtls_gcm_context *ctx );
 
+#ifdef __cplusplus
+}
+#endif
+
+#else  /* !MBEDTLS_GCM_ALT */
+#include "gcm_alt.h"
+#endif /* !MBEDTLS_GCM_ALT */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
 /**
  * \brief          Checkup routine
  *
@@ -217,4 +231,5 @@ int mbedtls_gcm_self_test( int verbose );
 }
 #endif
 
+
 #endif /* gcm.h */
diff --git a/include/mbedtls/timing.h b/include/mbedtls/timing.h
index ae7a713e7..bfb8579a0 100644
--- a/include/mbedtls/timing.h
+++ b/include/mbedtls/timing.h
@@ -1,7 +1,7 @@
 /**
  * \file timing.h
  *
- * \brief Portable interface to the CPU cycle counter
+ * \brief Portable interface to timeouts and to the CPU cycle counter
  *
  *  Copyright (C) 2006-2015, ARM Limited, All Rights Reserved
  *  SPDX-License-Identifier: Apache-2.0
@@ -65,6 +65,9 @@ extern volatile int mbedtls_timing_alarmed;
  * \warning        This is only a best effort! Do not rely on this!
  *                 In particular, it is known to be unreliable on virtual
  *                 machines.
+ *
+ * \note           This value starts at an unspecified origin and
+ *                 may wrap around.
  */
 unsigned long mbedtls_timing_hardclock( void );
 
@@ -72,7 +75,18 @@ unsigned long mbedtls_timing_hardclock( void );
  * \brief          Return the elapsed time in milliseconds
  *
  * \param val      points to a timer structure
- * \param reset    if set to 1, the timer is restarted
+ * \param reset    If 0, query the elapsed time. Otherwise (re)start the timer.
+ *
+ * \return         Elapsed time since the previous reset in ms. When
+ *                 restarting, this is always 0.
+ *
+ * \note           To initialize a timer, call this function with reset=1.
+ *
+ *                 Determining the elapsed time and resetting the timer is not
+ *                 atomic on all platforms, so after the sequence
+ *                 `{ get_timer(1); ...; time1 = get_timer(1); ...; time2 =
+ *                 get_timer(0) }` the value time1+time2 is only approximately
+ *                 the delay since the first reset.
  */
 unsigned long mbedtls_timing_get_timer( struct mbedtls_timing_hr_time *val, int reset );
 
@@ -80,6 +94,7 @@ unsigned long mbedtls_timing_get_timer( struct mbedtls_timing_hr_time *val, int
  * \brief          Setup an alarm clock
  *
  * \param seconds  delay before the "mbedtls_timing_alarmed" flag is set
+ *                 (must be >=0)
  *
  * \warning        Only one alarm at a time  is supported. In a threaded
  *                 context, this means one for the whole process, not one per
@@ -91,11 +106,15 @@ void mbedtls_set_alarm( int seconds );
  * \brief          Set a pair of delays to watch
  *                 (See \c mbedtls_timing_get_delay().)
  *
- * \param data     Pointer to timing data
+ * \param data     Pointer to timing data.
  *                 Must point to a valid \c mbedtls_timing_delay_context struct.
  * \param int_ms   First (intermediate) delay in milliseconds.
+ *                 The effect if int_ms > fin_ms is unspecified.
  * \param fin_ms   Second (final) delay in milliseconds.
  *                 Pass 0 to cancel the current delay.
+ *
+ * \note           To set a single delay, either use \c mbedtls_timing_set_timer
+ *                 directly or use this function with int_ms == fin_ms.
  */
 void mbedtls_timing_set_delay( void *data, uint32_t int_ms, uint32_t fin_ms );
 
@@ -106,7 +125,7 @@ void mbedtls_timing_set_delay( void *data, uint32_t int_ms, uint32_t fin_ms );
  * \param data     Pointer to timing data
  *                 Must point to a valid \c mbedtls_timing_delay_context struct.
  *
- * \return         -1 if cancelled (fin_ms = 0)
+ * \return         -1 if cancelled (fin_ms = 0),
  *                  0 if none of the delays are passed,
  *                  1 if only the intermediate delay is passed,
  *                  2 if the final delay is passed.
diff --git a/library/aes.c b/library/aes.c
index 58603849c..dba4a5f57 100644
--- a/library/aes.c
+++ b/library/aes.c
@@ -1235,9 +1235,11 @@ static const int aes_test_ctr_len[3] =
  */
 int mbedtls_aes_self_test( int verbose )
 {
-    int ret = 0, i, j, u, v;
+    int ret = 0, i, j, u, mode;
+    unsigned int keybits;
     unsigned char key[32];
     unsigned char buf[64];
+    const unsigned char *aes_tests;
 #if defined(MBEDTLS_CIPHER_MODE_CBC) || defined(MBEDTLS_CIPHER_MODE_CFB)
     unsigned char iv[16];
 #endif
@@ -1263,45 +1265,52 @@ int mbedtls_aes_self_test( int verbose )
     for( i = 0; i < 6; i++ )
     {
         u = i >> 1;
-        v = i  & 1;
+        keybits = 128 + u * 64;
+        mode = i & 1;
 
         if( verbose != 0 )
-            mbedtls_printf( "  AES-ECB-%3d (%s): ", 128 + u * 64,
-                             ( v == MBEDTLS_AES_DECRYPT ) ? "dec" : "enc" );
+            mbedtls_printf( "  AES-ECB-%3d (%s): ", keybits,
+                            ( mode == MBEDTLS_AES_DECRYPT ) ? "dec" : "enc" );
 
         memset( buf, 0, 16 );
 
-        if( v == MBEDTLS_AES_DECRYPT )
+        if( mode == MBEDTLS_AES_DECRYPT )
         {
-            mbedtls_aes_setkey_dec( &ctx, key, 128 + u * 64 );
-
-            for( j = 0; j < 10000; j++ )
-                mbedtls_aes_crypt_ecb( &ctx, v, buf, buf );
-
-            if( memcmp( buf, aes_test_ecb_dec[u], 16 ) != 0 )
-            {
-                if( verbose != 0 )
-                    mbedtls_printf( "failed\n" );
-
-                ret = 1;
-                goto exit;
-            }
+            ret = mbedtls_aes_setkey_dec( &ctx, key, keybits );
+            aes_tests = aes_test_ecb_dec[u];
         }
         else
         {
-            mbedtls_aes_setkey_enc( &ctx, key, 128 + u * 64 );
+            ret = mbedtls_aes_setkey_enc( &ctx, key, keybits );
+            aes_tests = aes_test_ecb_enc[u];
+        }
 
-            for( j = 0; j < 10000; j++ )
-                mbedtls_aes_crypt_ecb( &ctx, v, buf, buf );
+        /*
+         * AES-192 is an optional feature that may be unavailable when
+         * there is an alternative underlying implementation i.e. when
+         * MBEDTLS_AES_ALT is defined.
+         */
+        if( ret == MBEDTLS_ERR_AES_FEATURE_UNAVAILABLE && keybits == 192 )
+        {
+            mbedtls_printf( "skipped\n" );
+            continue;
+        }
+        else if( ret != 0 )
+        {
+            goto exit;
+        }
 
-            if( memcmp( buf, aes_test_ecb_enc[u], 16 ) != 0 )
-            {
-                if( verbose != 0 )
-                    mbedtls_printf( "failed\n" );
-
-                ret = 1;
+        for( j = 0; j < 10000; j++ )
+        {
+            ret = mbedtls_aes_crypt_ecb( &ctx, mode, buf, buf );
+            if( ret != 0 )
                 goto exit;
-            }
+        }
+
+        if( memcmp( buf, aes_tests, 16 ) != 0 )
+        {
+            ret = 1;
+            goto exit;
         }
 
         if( verbose != 0 )
@@ -1318,55 +1327,64 @@ int mbedtls_aes_self_test( int verbose )
     for( i = 0; i < 6; i++ )
     {
         u = i >> 1;
-        v = i  & 1;
+        keybits = 128 + u * 64;
+        mode = i & 1;
 
         if( verbose != 0 )
-            mbedtls_printf( "  AES-CBC-%3d (%s): ", 128 + u * 64,
-                             ( v == MBEDTLS_AES_DECRYPT ) ? "dec" : "enc" );
+            mbedtls_printf( "  AES-CBC-%3d (%s): ", keybits,
+                            ( mode == MBEDTLS_AES_DECRYPT ) ? "dec" : "enc" );
 
         memset( iv , 0, 16 );
         memset( prv, 0, 16 );
         memset( buf, 0, 16 );
 
-        if( v == MBEDTLS_AES_DECRYPT )
+        if( mode == MBEDTLS_AES_DECRYPT )
         {
-            mbedtls_aes_setkey_dec( &ctx, key, 128 + u * 64 );
-
-            for( j = 0; j < 10000; j++ )
-                mbedtls_aes_crypt_cbc( &ctx, v, 16, iv, buf, buf );
-
-            if( memcmp( buf, aes_test_cbc_dec[u], 16 ) != 0 )
-            {
-                if( verbose != 0 )
-                    mbedtls_printf( "failed\n" );
-
-                ret = 1;
-                goto exit;
-            }
+            ret = mbedtls_aes_setkey_dec( &ctx, key, keybits );
+            aes_tests = aes_test_cbc_dec[u];
         }
         else
         {
-            mbedtls_aes_setkey_enc( &ctx, key, 128 + u * 64 );
+            ret = mbedtls_aes_setkey_enc( &ctx, key, keybits );
+            aes_tests = aes_test_cbc_enc[u];
+        }
 
-            for( j = 0; j < 10000; j++ )
+        /*
+         * AES-192 is an optional feature that may be unavailable when
+         * there is an alternative underlying implementation i.e. when
+         * MBEDTLS_AES_ALT is defined.
+         */
+        if( ret == MBEDTLS_ERR_AES_FEATURE_UNAVAILABLE && keybits == 192 )
+        {
+            mbedtls_printf( "skipped\n" );
+            continue;
+        }
+        else if( ret != 0 )
+        {
+            goto exit;
+        }
+
+        for( j = 0; j < 10000; j++ )
+        {
+            if( mode == MBEDTLS_AES_ENCRYPT )
             {
                 unsigned char tmp[16];
 
-                mbedtls_aes_crypt_cbc( &ctx, v, 16, iv, buf, buf );
-
                 memcpy( tmp, prv, 16 );
                 memcpy( prv, buf, 16 );
                 memcpy( buf, tmp, 16 );
             }
 
-            if( memcmp( prv, aes_test_cbc_enc[u], 16 ) != 0 )
-            {
-                if( verbose != 0 )
-                    mbedtls_printf( "failed\n" );
-
-                ret = 1;
+            ret = mbedtls_aes_crypt_cbc( &ctx, mode, 16, iv, buf, buf );
+            if( ret != 0 )
                 goto exit;
-            }
+
+        }
+
+        if( memcmp( buf, aes_tests, 16 ) != 0 )
+        {
+            ret = 1;
+            goto exit;
         }
 
         if( verbose != 0 )
@@ -1384,45 +1402,52 @@ int mbedtls_aes_self_test( int verbose )
     for( i = 0; i < 6; i++ )
     {
         u = i >> 1;
-        v = i  & 1;
+        keybits = 128 + u * 64;
+        mode = i & 1;
 
         if( verbose != 0 )
-            mbedtls_printf( "  AES-CFB128-%3d (%s): ", 128 + u * 64,
-                             ( v == MBEDTLS_AES_DECRYPT ) ? "dec" : "enc" );
+            mbedtls_printf( "  AES-CFB128-%3d (%s): ", keybits,
+                            ( mode == MBEDTLS_AES_DECRYPT ) ? "dec" : "enc" );
 
         memcpy( iv,  aes_test_cfb128_iv, 16 );
-        memcpy( key, aes_test_cfb128_key[u], 16 + u * 8 );
+        memcpy( key, aes_test_cfb128_key[u], keybits / 8 );
 
         offset = 0;
-        mbedtls_aes_setkey_enc( &ctx, key, 128 + u * 64 );
+        ret = mbedtls_aes_setkey_enc( &ctx, key, keybits );
+        /*
+         * AES-192 is an optional feature that may be unavailable when
+         * there is an alternative underlying implementation i.e. when
+         * MBEDTLS_AES_ALT is defined.
+         */
+        if( ret == MBEDTLS_ERR_AES_FEATURE_UNAVAILABLE && keybits == 192 )
+        {
+            mbedtls_printf( "skipped\n" );
+            continue;
+        }
+        else if( ret != 0 )
+        {
+            goto exit;
+        }
 
-        if( v == MBEDTLS_AES_DECRYPT )
+        if( mode == MBEDTLS_AES_DECRYPT )
         {
             memcpy( buf, aes_test_cfb128_ct[u], 64 );
-            mbedtls_aes_crypt_cfb128( &ctx, v, 64, &offset, iv, buf, buf );
-
-            if( memcmp( buf, aes_test_cfb128_pt, 64 ) != 0 )
-            {
-                if( verbose != 0 )
-                    mbedtls_printf( "failed\n" );
-
-                ret = 1;
-                goto exit;
-            }
+            aes_tests = aes_test_cfb128_pt;
         }
         else
         {
             memcpy( buf, aes_test_cfb128_pt, 64 );
-            mbedtls_aes_crypt_cfb128( &ctx, v, 64, &offset, iv, buf, buf );
+            aes_tests = aes_test_cfb128_ct[u];
+        }
 
-            if( memcmp( buf, aes_test_cfb128_ct[u], 64 ) != 0 )
-            {
-                if( verbose != 0 )
-                    mbedtls_printf( "failed\n" );
+        ret = mbedtls_aes_crypt_cfb128( &ctx, mode, 64, &offset, iv, buf, buf );
+        if( ret != 0 )
+            goto exit;
 
-                ret = 1;
-                goto exit;
-            }
+        if( memcmp( buf, aes_tests, 64 ) != 0 )
+        {
+            ret = 1;
+            goto exit;
         }
 
         if( verbose != 0 )
@@ -1440,51 +1465,41 @@ int mbedtls_aes_self_test( int verbose )
     for( i = 0; i < 6; i++ )
     {
         u = i >> 1;
-        v = i  & 1;
+        mode = i & 1;
 
         if( verbose != 0 )
             mbedtls_printf( "  AES-CTR-128 (%s): ",
-                             ( v == MBEDTLS_AES_DECRYPT ) ? "dec" : "enc" );
+                            ( mode == MBEDTLS_AES_DECRYPT ) ? "dec" : "enc" );
 
         memcpy( nonce_counter, aes_test_ctr_nonce_counter[u], 16 );
         memcpy( key, aes_test_ctr_key[u], 16 );
 
         offset = 0;
-        mbedtls_aes_setkey_enc( &ctx, key, 128 );
+        if( ( ret = mbedtls_aes_setkey_enc( &ctx, key, 128 ) ) != 0 )
+            goto exit;
 
-        if( v == MBEDTLS_AES_DECRYPT )
+        len = aes_test_ctr_len[u];
+
+        if( mode == MBEDTLS_AES_DECRYPT )
         {
-            len = aes_test_ctr_len[u];
             memcpy( buf, aes_test_ctr_ct[u], len );
-
-            mbedtls_aes_crypt_ctr( &ctx, len, &offset, nonce_counter, stream_block,
-                           buf, buf );
-
-            if( memcmp( buf, aes_test_ctr_pt[u], len ) != 0 )
-            {
-                if( verbose != 0 )
-                    mbedtls_printf( "failed\n" );
-
-                ret = 1;
-                goto exit;
-            }
+            aes_tests = aes_test_ctr_pt[u];
         }
         else
         {
-            len = aes_test_ctr_len[u];
             memcpy( buf, aes_test_ctr_pt[u], len );
+            aes_tests = aes_test_ctr_ct[u];
+        }
 
-            mbedtls_aes_crypt_ctr( &ctx, len, &offset, nonce_counter, stream_block,
-                           buf, buf );
+        ret = mbedtls_aes_crypt_ctr( &ctx, len, &offset, nonce_counter,
+                                     stream_block, buf, buf );
+        if( ret != 0 )
+            goto exit;
 
-            if( memcmp( buf, aes_test_ctr_ct[u], len ) != 0 )
-            {
-                if( verbose != 0 )
-                    mbedtls_printf( "failed\n" );
-
-                ret = 1;
-                goto exit;
-            }
+        if( memcmp( buf, aes_tests, len ) != 0 )
+        {
+            ret = 1;
+            goto exit;
         }
 
         if( verbose != 0 )
@@ -1498,6 +1513,9 @@ int mbedtls_aes_self_test( int verbose )
     ret = 0;
 
 exit:
+    if( ret != 0 && verbose != 0 )
+        mbedtls_printf( "failed\n" );
+
     mbedtls_aes_free( &ctx );
 
     return( ret );
diff --git a/library/ccm.c b/library/ccm.c
index 13a8fd1a2..9101e5f7c 100644
--- a/library/ccm.c
+++ b/library/ccm.c
@@ -49,6 +49,8 @@
 #endif /* MBEDTLS_PLATFORM_C */
 #endif /* MBEDTLS_SELF_TEST && MBEDTLS_AES_C */
 
+#if !defined(MBEDTLS_CCM_ALT)
+
 /* Implementation that should never be optimized out by the compiler */
 static void mbedtls_zeroize( void *v, size_t n ) {
     volatile unsigned char *p = (unsigned char*)v; while( n-- ) *p++ = 0;
@@ -348,6 +350,7 @@ int mbedtls_ccm_auth_decrypt( mbedtls_ccm_context *ctx, size_t length,
     return( 0 );
 }
 
+#endif /* !MBEDTLS_CCM_ALT */
 
 #if defined(MBEDTLS_SELF_TEST) && defined(MBEDTLS_AES_C)
 /*
diff --git a/library/cmac.c b/library/cmac.c
index 6df56aa9a..9dbff9038 100644
--- a/library/cmac.c
+++ b/library/cmac.c
@@ -65,6 +65,8 @@
 #endif /* MBEDTLS_SELF_TEST */
 #endif /* MBEDTLS_PLATFORM_C */
 
+#if !defined(MBEDTLS_CMAC_ALT) || defined(MBEDTLS_SELF_TEST)
+
 /* Implementation that should never be optimized out by the compiler */
 static void mbedtls_zeroize( void *v, size_t n ) {
     volatile unsigned char *p = (unsigned char*)v; while( n-- ) *p++ = 0;
@@ -164,7 +166,9 @@ exit:
 
     return( ret );
 }
+#endif /* !defined(MBEDTLS_CMAC_ALT) || defined(MBEDTLS_SELF_TEST) */
 
+#if !defined(MBEDTLS_CMAC_ALT)
 static void cmac_xor_block( unsigned char *output, const unsigned char *input1,
                             const unsigned char *input2,
                             const size_t block_size )
@@ -468,6 +472,8 @@ exit:
 }
 #endif /* MBEDTLS_AES_C */
 
+#endif /* !MBEDTLS_CMAC_ALT */
+
 #if defined(MBEDTLS_SELF_TEST)
 /*
  * CMAC test data for SP800-38B
diff --git a/library/error.c b/library/error.c
index 23e4953fc..151ca4eae 100644
--- a/library/error.c
+++ b/library/error.c
@@ -520,6 +520,8 @@ void mbedtls_strerror( int ret, char *buf, size_t buflen )
         mbedtls_snprintf( buf, buflen, "AES - Invalid key length" );
     if( use_ret == -(MBEDTLS_ERR_AES_INVALID_INPUT_LENGTH) )
         mbedtls_snprintf( buf, buflen, "AES - Invalid data input length" );
+    if( use_ret == -(MBEDTLS_ERR_AES_FEATURE_UNAVAILABLE) )
+        mbedtls_snprintf( buf, buflen, "AES - Feature not available, e.g. unsupported AES key size" );
 #endif /* MBEDTLS_AES_C */
 
 #if defined(MBEDTLS_ASN1_PARSE_C)
diff --git a/library/gcm.c b/library/gcm.c
index fccb092bd..294a86d3d 100644
--- a/library/gcm.c
+++ b/library/gcm.c
@@ -46,6 +46,7 @@
 #endif
 
 #if defined(MBEDTLS_SELF_TEST) && defined(MBEDTLS_AES_C)
+#include "mbedtls/aes.h"
 #if defined(MBEDTLS_PLATFORM_C)
 #include "mbedtls/platform.h"
 #else
@@ -54,6 +55,8 @@
 #endif /* MBEDTLS_PLATFORM_C */
 #endif /* MBEDTLS_SELF_TEST && MBEDTLS_AES_C */
 
+#if !defined(MBEDTLS_GCM_ALT)
+
 /*
  * 32-bit integer manipulation macros (big endian)
  */
@@ -508,6 +511,8 @@ void mbedtls_gcm_free( mbedtls_gcm_context *ctx )
     mbedtls_zeroize( ctx, sizeof( mbedtls_gcm_context ) );
 }
 
+#endif /* !MBEDTLS_GCM_ALT */
+
 #if defined(MBEDTLS_SELF_TEST) && defined(MBEDTLS_AES_C)
 /*
  * AES-GCM test vectors from:
@@ -744,34 +749,48 @@ int mbedtls_gcm_self_test( int verbose )
     int i, j, ret;
     mbedtls_cipher_id_t cipher = MBEDTLS_CIPHER_ID_AES;
 
-    mbedtls_gcm_init( &ctx );
-
     for( j = 0; j < 3; j++ )
     {
         int key_len = 128 + 64 * j;
 
         for( i = 0; i < MAX_TESTS; i++ )
         {
+            mbedtls_gcm_init( &ctx );
+
             if( verbose != 0 )
                 mbedtls_printf( "  AES-GCM-%3d #%d (%s): ",
-                                 key_len, i, "enc" );
+                                key_len, i, "enc" );
 
-            mbedtls_gcm_setkey( &ctx, cipher, key[key_index[i]], key_len );
+            ret = mbedtls_gcm_setkey( &ctx, cipher, key[key_index[i]],
+                                      key_len );
+            /*
+             * AES-192 is an optional feature that may be unavailable when
+             * there is an alternative underlying implementation i.e. when
+             * MBEDTLS_AES_ALT is defined.
+             */
+            if( ret == MBEDTLS_ERR_AES_FEATURE_UNAVAILABLE && key_len == 192 )
+            {
+                mbedtls_printf( "skipped\n" );
+                break;
+            }
+            else if( ret != 0 )
+            {
+                goto exit;
+            }
 
             ret = mbedtls_gcm_crypt_and_tag( &ctx, MBEDTLS_GCM_ENCRYPT,
-                                     pt_len[i],
-                                     iv[iv_index[i]], iv_len[i],
-                                     additional[add_index[i]], add_len[i],
-                                     pt[pt_index[i]], buf, 16, tag_buf );
+                                        pt_len[i],
+                                        iv[iv_index[i]], iv_len[i],
+                                        additional[add_index[i]], add_len[i],
+                                        pt[pt_index[i]], buf, 16, tag_buf );
+            if( ret != 0 )
+                goto exit;
 
-            if( ret != 0 ||
-                memcmp( buf, ct[j * 6 + i], pt_len[i] ) != 0 ||
-                memcmp( tag_buf, tag[j * 6 + i], 16 ) != 0 )
+            if ( memcmp( buf, ct[j * 6 + i], pt_len[i] ) != 0 ||
+                 memcmp( tag_buf, tag[j * 6 + i], 16 ) != 0 )
             {
-                if( verbose != 0 )
-                    mbedtls_printf( "failed\n" );
-
-                return( 1 );
+                ret = 1;
+                goto exit;
             }
 
             mbedtls_gcm_free( &ctx );
@@ -779,26 +798,31 @@ int mbedtls_gcm_self_test( int verbose )
             if( verbose != 0 )
                 mbedtls_printf( "passed\n" );
 
+            mbedtls_gcm_init( &ctx );
+
             if( verbose != 0 )
                 mbedtls_printf( "  AES-GCM-%3d #%d (%s): ",
-                                 key_len, i, "dec" );
+                                key_len, i, "dec" );
 
-            mbedtls_gcm_setkey( &ctx, cipher, key[key_index[i]], key_len );
+            ret = mbedtls_gcm_setkey( &ctx, cipher, key[key_index[i]],
+                                      key_len );
+            if( ret != 0 )
+                goto exit;
 
             ret = mbedtls_gcm_crypt_and_tag( &ctx, MBEDTLS_GCM_DECRYPT,
-                                     pt_len[i],
-                                     iv[iv_index[i]], iv_len[i],
-                                     additional[add_index[i]], add_len[i],
-                                     ct[j * 6 + i], buf, 16, tag_buf );
+                                        pt_len[i],
+                                        iv[iv_index[i]], iv_len[i],
+                                        additional[add_index[i]], add_len[i],
+                                        ct[j * 6 + i], buf, 16, tag_buf );
 
-            if( ret != 0 ||
-                memcmp( buf, pt[pt_index[i]], pt_len[i] ) != 0 ||
+            if( ret != 0 )
+                goto exit;
+
+            if( memcmp( buf, pt[pt_index[i]], pt_len[i] ) != 0 ||
                 memcmp( tag_buf, tag[j * 6 + i], 16 ) != 0 )
             {
-                if( verbose != 0 )
-                    mbedtls_printf( "failed\n" );
-
-                return( 1 );
+                ret = 1;
+                goto exit;
             }
 
             mbedtls_gcm_free( &ctx );
@@ -806,66 +830,51 @@ int mbedtls_gcm_self_test( int verbose )
             if( verbose != 0 )
                 mbedtls_printf( "passed\n" );
 
+            mbedtls_gcm_init( &ctx );
+
             if( verbose != 0 )
                 mbedtls_printf( "  AES-GCM-%3d #%d split (%s): ",
-                                 key_len, i, "enc" );
+                                key_len, i, "enc" );
 
-            mbedtls_gcm_setkey( &ctx, cipher, key[key_index[i]], key_len );
+            ret = mbedtls_gcm_setkey( &ctx, cipher, key[key_index[i]],
+                                      key_len );
+            if( ret != 0 )
+                goto exit;
 
             ret = mbedtls_gcm_starts( &ctx, MBEDTLS_GCM_ENCRYPT,
-                              iv[iv_index[i]], iv_len[i],
-                              additional[add_index[i]], add_len[i] );
+                                      iv[iv_index[i]], iv_len[i],
+                                      additional[add_index[i]], add_len[i] );
             if( ret != 0 )
-            {
-                if( verbose != 0 )
-                    mbedtls_printf( "failed\n" );
-
-                return( 1 );
-            }
+                goto exit;
 
             if( pt_len[i] > 32 )
             {
                 size_t rest_len = pt_len[i] - 32;
                 ret = mbedtls_gcm_update( &ctx, 32, pt[pt_index[i]], buf );
                 if( ret != 0 )
-                {
-                    if( verbose != 0 )
-                        mbedtls_printf( "failed\n" );
-
-                    return( 1 );
-                }
+                    goto exit;
 
                 ret = mbedtls_gcm_update( &ctx, rest_len, pt[pt_index[i]] + 32,
                                   buf + 32 );
                 if( ret != 0 )
-                {
-                    if( verbose != 0 )
-                        mbedtls_printf( "failed\n" );
-
-                    return( 1 );
-                }
+                    goto exit;
             }
             else
             {
                 ret = mbedtls_gcm_update( &ctx, pt_len[i], pt[pt_index[i]], buf );
                 if( ret != 0 )
-                {
-                    if( verbose != 0 )
-                        mbedtls_printf( "failed\n" );
-
-                    return( 1 );
-                }
+                    goto exit;
             }
 
             ret = mbedtls_gcm_finish( &ctx, tag_buf, 16 );
-            if( ret != 0 ||
-                memcmp( buf, ct[j * 6 + i], pt_len[i] ) != 0 ||
+            if( ret != 0 )
+                goto exit;
+
+            if( memcmp( buf, ct[j * 6 + i], pt_len[i] ) != 0 ||
                 memcmp( tag_buf, tag[j * 6 + i], 16 ) != 0 )
             {
-                if( verbose != 0 )
-                    mbedtls_printf( "failed\n" );
-
-                return( 1 );
+                ret = 1;
+                goto exit;
             }
 
             mbedtls_gcm_free( &ctx );
@@ -873,80 +882,75 @@ int mbedtls_gcm_self_test( int verbose )
             if( verbose != 0 )
                 mbedtls_printf( "passed\n" );
 
+            mbedtls_gcm_init( &ctx );
+
             if( verbose != 0 )
                 mbedtls_printf( "  AES-GCM-%3d #%d split (%s): ",
-                                 key_len, i, "dec" );
+                                key_len, i, "dec" );
 
-            mbedtls_gcm_setkey( &ctx, cipher, key[key_index[i]], key_len );
+            ret = mbedtls_gcm_setkey( &ctx, cipher, key[key_index[i]],
+                                      key_len );
+            if( ret != 0 )
+                goto exit;
 
             ret = mbedtls_gcm_starts( &ctx, MBEDTLS_GCM_DECRYPT,
                               iv[iv_index[i]], iv_len[i],
                               additional[add_index[i]], add_len[i] );
             if( ret != 0 )
-            {
-                if( verbose != 0 )
-                    mbedtls_printf( "failed\n" );
-
-                return( 1 );
-            }
+                goto exit;
 
             if( pt_len[i] > 32 )
             {
                 size_t rest_len = pt_len[i] - 32;
                 ret = mbedtls_gcm_update( &ctx, 32, ct[j * 6 + i], buf );
                 if( ret != 0 )
-                {
-                    if( verbose != 0 )
-                        mbedtls_printf( "failed\n" );
-
-                    return( 1 );
-                }
+                    goto exit;
 
                 ret = mbedtls_gcm_update( &ctx, rest_len, ct[j * 6 + i] + 32,
-                                  buf + 32 );
+                                          buf + 32 );
                 if( ret != 0 )
-                {
-                    if( verbose != 0 )
-                        mbedtls_printf( "failed\n" );
-
-                    return( 1 );
-                }
+                    goto exit;
             }
             else
             {
-                ret = mbedtls_gcm_update( &ctx, pt_len[i], ct[j * 6 + i], buf );
+                ret = mbedtls_gcm_update( &ctx, pt_len[i], ct[j * 6 + i],
+                                          buf );
                 if( ret != 0 )
-                {
-                    if( verbose != 0 )
-                        mbedtls_printf( "failed\n" );
-
-                    return( 1 );
-                }
+                    goto exit;
             }
 
             ret = mbedtls_gcm_finish( &ctx, tag_buf, 16 );
-            if( ret != 0 ||
-                memcmp( buf, pt[pt_index[i]], pt_len[i] ) != 0 ||
+            if( ret != 0 )
+                goto exit;
+
+            if( memcmp( buf, pt[pt_index[i]], pt_len[i] ) != 0 ||
                 memcmp( tag_buf, tag[j * 6 + i], 16 ) != 0 )
             {
-                if( verbose != 0 )
-                    mbedtls_printf( "failed\n" );
-
-                return( 1 );
+                ret = 1;
+                goto exit;
             }
 
             mbedtls_gcm_free( &ctx );
 
             if( verbose != 0 )
                 mbedtls_printf( "passed\n" );
-
         }
     }
 
     if( verbose != 0 )
         mbedtls_printf( "\n" );
 
-    return( 0 );
+    ret = 0;
+
+exit:
+    if( ret != 0 )
+    {
+        if( verbose != 0 )
+            mbedtls_printf( "failed\n" );
+        mbedtls_gcm_free( &ctx );
+    }
+
+    return( ret );
 }
 
 #endif /* MBEDTLS_SELF_TEST && MBEDTLS_AES_C */
diff --git a/library/timing.c b/library/timing.c
index a7c7ff027..6df137d2d 100644
--- a/library/timing.c
+++ b/library/timing.c
@@ -244,21 +244,23 @@ volatile int mbedtls_timing_alarmed = 0;
 
 unsigned long mbedtls_timing_get_timer( struct mbedtls_timing_hr_time *val, int reset )
 {
-    unsigned long delta;
-    LARGE_INTEGER offset, hfreq;
     struct _hr_time *t = (struct _hr_time *) val;
 
-    QueryPerformanceCounter(  &offset );
-    QueryPerformanceFrequency( &hfreq );
-
-    delta = (unsigned long)( ( 1000 *
-        ( offset.QuadPart - t->start.QuadPart ) ) /
-           hfreq.QuadPart );
-
     if( reset )
+    {
         QueryPerformanceCounter( &t->start );
-
-    return( delta );
+        return( 0 );
+    }
+    else
+    {
+        unsigned long delta;
+        LARGE_INTEGER now, hfreq;
+        QueryPerformanceCounter(  &now );
+        QueryPerformanceFrequency( &hfreq );
+        delta = (unsigned long)( ( now.QuadPart - t->start.QuadPart ) * 1000ul
+                                 / hfreq.QuadPart );
+        return( delta );
+    }
 }
 
 /* It's OK to use a global because alarm() is supposed to be global anyway */
@@ -285,23 +287,22 @@ void mbedtls_set_alarm( int seconds )
 
 unsigned long mbedtls_timing_get_timer( struct mbedtls_timing_hr_time *val, int reset )
 {
-    unsigned long delta;
-    struct timeval offset;
     struct _hr_time *t = (struct _hr_time *) val;
 
-    gettimeofday( &offset, NULL );
-
     if( reset )
     {
-        t->start.tv_sec  = offset.tv_sec;
-        t->start.tv_usec = offset.tv_usec;
+        gettimeofday( &t->start, NULL );
         return( 0 );
     }
-
-    delta = ( offset.tv_sec  - t->start.tv_sec  ) * 1000
-          + ( offset.tv_usec - t->start.tv_usec ) / 1000;
-
-    return( delta );
+    else
+    {
+        unsigned long delta;
+        struct timeval now;
+        gettimeofday( &now, NULL );
+        delta = ( now.tv_sec  - t->start.tv_sec  ) * 1000ul
+              + ( now.tv_usec - t->start.tv_usec ) / 1000;
+        return( delta );
+    }
 }
 
 static void sighandler( int signum )
@@ -315,6 +316,12 @@ void mbedtls_set_alarm( int seconds )
     mbedtls_timing_alarmed = 0;
     signal( SIGALRM, sighandler );
     alarm( seconds );
+    if( seconds == 0 )
+    {
+        /* alarm(0) cancelled any previous pending alarm, but the
+           handler won't fire, so raise the flag straight away. */
+        mbedtls_timing_alarmed = 1;
+    }
 }
 
 #endif /* _WIN32 && !EFIX64 && !EFI32 */
@@ -378,13 +385,21 @@ static void busy_msleep( unsigned long msec )
     (void) j;
 }
 
-#define FAIL    do                      \
-{                                       \
-    if( verbose != 0 )                  \
-        mbedtls_printf( "failed\n" );   \
-                                        \
-    return( 1 );                        \
-} while( 0 )
+#define FAIL    do                                                      \
+    {                                                                   \
+        if( verbose != 0 )                                              \
+        {                                                               \
+            mbedtls_printf( "failed at line %d\n", __LINE__ );          \
+            mbedtls_printf( " cycles=%lu ratio=%lu millisecs=%lu secs=%lu hardfail=%d a=%lu b=%lu\n", \
+                            cycles, ratio, millisecs, secs, hardfail,   \
+                            (unsigned long) a, (unsigned long) b );     \
+            mbedtls_printf( " elapsed(hires)=%lu elapsed(ctx)=%lu status(ctx)=%d\n", \
+                            mbedtls_timing_get_timer( &hires, 0 ),      \
+                            mbedtls_timing_get_timer( &ctx.timer, 0 ),  \
+                            mbedtls_timing_get_delay( &ctx ) );         \
+        }                                                               \
+        return( 1 );                                                    \
+    } while( 0 )
 
 /*
  * Checkup routine
@@ -394,22 +409,22 @@ static void busy_msleep( unsigned long msec )
  */
 int mbedtls_timing_self_test( int verbose )
 {
-    unsigned long cycles, ratio;
-    unsigned long millisecs, secs;
-    int hardfail;
+    unsigned long cycles = 0, ratio = 0;
+    unsigned long millisecs = 0, secs = 0;
+    int hardfail = 0;
     struct mbedtls_timing_hr_time hires;
-    uint32_t a, b;
+    uint32_t a = 0, b = 0;
     mbedtls_timing_delay_context ctx;
 
     if( verbose != 0 )
         mbedtls_printf( "  TIMING tests note: will take some time!\n" );
 
-
     if( verbose != 0 )
         mbedtls_printf( "  TIMING test #1 (set_alarm / get_timer): " );
 
-    for( secs = 1; secs <= 3; secs++ )
     {
+        secs = 1;
+
         (void) mbedtls_timing_get_timer( &hires, 1 );
 
         mbedtls_set_alarm( (int) secs );
@@ -421,12 +436,7 @@ int mbedtls_timing_self_test( int verbose )
         /* For some reason on Windows it looks like alarm has an extra delay
          * (maybe related to creating a new thread). Allow some room here. */
         if( millisecs < 800 * secs || millisecs > 1200 * secs + 300 )
-        {
-            if( verbose != 0 )
-                mbedtls_printf( "failed\n" );
-
-            return( 1 );
-        }
+            FAIL;
     }
 
     if( verbose != 0 )
@@ -435,28 +445,22 @@ int mbedtls_timing_self_test( int verbose )
     if( verbose != 0 )
         mbedtls_printf( "  TIMING test #2 (set/get_delay        ): " );
 
-    for( a = 200; a <= 400; a += 200 )
     {
-        for( b = 200; b <= 400; b += 200 )
-        {
-            mbedtls_timing_set_delay( &ctx, a, a + b );
+        a = 800;
+        b = 400;
+        mbedtls_timing_set_delay( &ctx, a, a + b );          /* T = 0 */
 
-            busy_msleep( a - a / 8 );
-            if( mbedtls_timing_get_delay( &ctx ) != 0 )
-                FAIL;
+        busy_msleep( a - a / 4 );                      /* T = a - a/4 */
+        if( mbedtls_timing_get_delay( &ctx ) != 0 )
+            FAIL;
 
-            busy_msleep( a / 4 );
-            if( mbedtls_timing_get_delay( &ctx ) != 1 )
-                FAIL;
+        busy_msleep( a / 4 + b / 4 );                  /* T = a + b/4 */
+        if( mbedtls_timing_get_delay( &ctx ) != 1 )
+            FAIL;
 
-            busy_msleep( b - a / 8 - b / 8 );
-            if( mbedtls_timing_get_delay( &ctx ) != 1 )
-                FAIL;
-
-            busy_msleep( b / 4 );
-            if( mbedtls_timing_get_delay( &ctx ) != 2 )
-                FAIL;
-        }
+        busy_msleep( b );                          /* T = a + b + b/4 */
+        if( mbedtls_timing_get_delay( &ctx ) != 2 )
+            FAIL;
     }
 
     mbedtls_timing_set_delay( &ctx, 0, 0 );
@@ -475,7 +479,6 @@ int mbedtls_timing_self_test( int verbose )
      * On a 4Ghz 32-bit machine the cycle counter wraps about once per second;
      * since the whole test is about 10ms, it shouldn't happen twice in a row.
      */
-    hardfail = 0;
 
 hard_test:
     if( hardfail > 1 )
diff --git a/library/version_features.c b/library/version_features.c
index 9bf6c61ec..cdb41616e 100644
--- a/library/version_features.c
+++ b/library/version_features.c
@@ -96,12 +96,21 @@ static const char *features[] = {
 #if defined(MBEDTLS_CAMELLIA_ALT)
     "MBEDTLS_CAMELLIA_ALT",
 #endif /* MBEDTLS_CAMELLIA_ALT */
+#if defined(MBEDTLS_CCM_ALT)
+    "MBEDTLS_CCM_ALT",
+#endif /* MBEDTLS_CCM_ALT */
+#if defined(MBEDTLS_CMAC_ALT)
+    "MBEDTLS_CMAC_ALT",
+#endif /* MBEDTLS_CMAC_ALT */
 #if defined(MBEDTLS_DES_ALT)
     "MBEDTLS_DES_ALT",
 #endif /* MBEDTLS_DES_ALT */
 #if defined(MBEDTLS_RSA_ALT)
     "MBEDTLS_RSA_ALT",
 #endif /* MBEDTLS_RSA_ALT */
+#if defined(MBEDTLS_GCM_ALT)
+    "MBEDTLS_GCM_ALT",
+#endif /* MBEDTLS_GCM_ALT */
 #if defined(MBEDTLS_XTEA_ALT)
     "MBEDTLS_XTEA_ALT",
 #endif /* MBEDTLS_XTEA_ALT */
diff --git a/programs/test/selftest.c b/programs/test/selftest.c
index 1941ad051..72a37342f 100644
--- a/programs/test/selftest.c
+++ b/programs/test/selftest.c
@@ -107,8 +107,8 @@ static int run_test_snprintf( void )
  * self-test. If this fails, we attempt the test anyway, so no error is passed
  * back.
  */
-#if defined(MBEDTLS_SELF_TEST) && defined(MBEDTLS_ENTROPY_C) && \
-    defined(MBEDTLS_ENTROPY_NV_SEED) && !defined(MBEDTLS_NO_PLATFORM_ENTROPY)
+#if defined(MBEDTLS_SELF_TEST) && defined(MBEDTLS_ENTROPY_C)
+#if defined(MBEDTLS_ENTROPY_NV_SEED) && !defined(MBEDTLS_NO_PLATFORM_ENTROPY)
 static void create_entropy_seed_file( void )
 {
     int result;
@@ -136,9 +136,137 @@ static void create_entropy_seed_file( void )
 }
 #endif
 
+int mbedtls_entropy_self_test_wrapper( int verbose )
+{
+#if defined(MBEDTLS_ENTROPY_NV_SEED) && !defined(MBEDTLS_NO_PLATFORM_ENTROPY)
+    create_entropy_seed_file( );
+#endif
+    return( mbedtls_entropy_self_test( verbose ) );
+}
+#endif
+
+#if defined(MBEDTLS_SELF_TEST)
+#if defined(MBEDTLS_MEMORY_BUFFER_ALLOC_C)
+int mbedtls_memory_buffer_alloc_free_and_self_test( int verbose )
+{
+    if( verbose != 0 )
+    {
+#if defined(MBEDTLS_MEMORY_DEBUG)
+        mbedtls_memory_buffer_alloc_status( );
+#endif
+    }
+    mbedtls_memory_buffer_alloc_free( );
+    return( mbedtls_memory_buffer_alloc_self_test( verbose ) );
+}
+#endif
+
+typedef struct
+{
+    const char *name;
+    int ( *function )( int );
+} selftest_t;
+
+const selftest_t selftests[] =
+{
+#if defined(MBEDTLS_MD2_C)
+    {"md2", mbedtls_md2_self_test},
+#endif
+#if defined(MBEDTLS_MD4_C)
+    {"md4", mbedtls_md4_self_test},
+#endif
+#if defined(MBEDTLS_MD5_C)
+    {"md5", mbedtls_md5_self_test},
+#endif
+#if defined(MBEDTLS_RIPEMD160_C)
+    {"ripemd160", mbedtls_ripemd160_self_test},
+#endif
+#if defined(MBEDTLS_SHA1_C)
+    {"sha1", mbedtls_sha1_self_test},
+#endif
+#if defined(MBEDTLS_SHA256_C)
+    {"sha256", mbedtls_sha256_self_test},
+#endif
+#if defined(MBEDTLS_SHA512_C)
+    {"sha512", mbedtls_sha512_self_test},
+#endif
+#if defined(MBEDTLS_ARC4_C)
+    {"arc4", mbedtls_arc4_self_test},
+#endif
+#if defined(MBEDTLS_DES_C)
+    {"des", mbedtls_des_self_test},
+#endif
+#if defined(MBEDTLS_AES_C)
+    {"aes", mbedtls_aes_self_test},
+#endif
+#if defined(MBEDTLS_GCM_C) && defined(MBEDTLS_AES_C)
+    {"gcm", mbedtls_gcm_self_test},
+#endif
+#if defined(MBEDTLS_CCM_C) && defined(MBEDTLS_AES_C)
+    {"ccm", mbedtls_ccm_self_test},
+#endif
+#if defined(MBEDTLS_CMAC_C)
+    {"cmac", mbedtls_cmac_self_test},
+#endif
+#if defined(MBEDTLS_BASE64_C)
+    {"base64", mbedtls_base64_self_test},
+#endif
+#if defined(MBEDTLS_BIGNUM_C)
+    {"mpi", mbedtls_mpi_self_test},
+#endif
+#if defined(MBEDTLS_RSA_C)
+    {"rsa", mbedtls_rsa_self_test},
+#endif
+#if defined(MBEDTLS_X509_USE_C)
+    {"x509", mbedtls_x509_self_test},
+#endif
+#if defined(MBEDTLS_XTEA_C)
+    {"xtea", mbedtls_xtea_self_test},
+#endif
+#if defined(MBEDTLS_CAMELLIA_C)
+    {"camellia", mbedtls_camellia_self_test},
+#endif
+#if defined(MBEDTLS_CTR_DRBG_C)
+    {"ctr_drbg", mbedtls_ctr_drbg_self_test},
+#endif
+#if defined(MBEDTLS_HMAC_DRBG_C)
+    {"hmac_drbg", mbedtls_hmac_drbg_self_test},
+#endif
+#if defined(MBEDTLS_ECP_C)
+    {"ecp", mbedtls_ecp_self_test},
+#endif
+#if defined(MBEDTLS_ECJPAKE_C)
+    {"ecjpake", mbedtls_ecjpake_self_test},
+#endif
+#if defined(MBEDTLS_DHM_C)
+    {"dhm", mbedtls_dhm_self_test},
+#endif
+#if defined(MBEDTLS_ENTROPY_C)
+    {"entropy", mbedtls_entropy_self_test_wrapper},
+#endif
+#if defined(MBEDTLS_PKCS5_C)
+    {"pkcs5", mbedtls_pkcs5_self_test},
+#endif
+/* Slower test after the faster ones */
+#if defined(MBEDTLS_TIMING_C)
+    {"timing", mbedtls_timing_self_test},
+#endif
+/* Heap test comes last */
+#if defined(MBEDTLS_MEMORY_BUFFER_ALLOC_C)
+    {"memory_buffer_alloc", mbedtls_memory_buffer_alloc_free_and_self_test},
+#endif
+    {NULL, NULL}
+};
+#endif /* MBEDTLS_SELF_TEST */
+
 int main( int argc, char *argv[] )
 {
-    int v, suites_tested = 0, suites_failed = 0;
+#if defined(MBEDTLS_SELF_TEST)
+    const selftest_t *test;
+#endif /* MBEDTLS_SELF_TEST */
+    char **argp;
+    int v = 1; /* v=1 for verbose mode */
+    int exclude_mode = 0;
+    int suites_tested = 0, suites_failed = 0;
 #if defined(MBEDTLS_MEMORY_BUFFER_ALLOC_C) && defined(MBEDTLS_SELF_TEST)
     unsigned char buf[1000000];
 #endif
@@ -165,16 +293,24 @@ int main( int argc, char *argv[] )
         mbedtls_exit( MBEDTLS_EXIT_FAILURE );
     }
 
-    if( argc == 2 && ( strcmp( argv[1], "--quiet" ) == 0  ||
-        strcmp( argv[1], "-q" ) == 0 ) )
+    for( argp = argv + ( argc >= 1 ? 1 : argc ); *argp != NULL; ++argp )
     {
-        v = 0;
+        if( strcmp( *argp, "--quiet" ) == 0 ||
+            strcmp( *argp, "-q" ) == 0 )
+        {
+            v = 0;
+        }
+        else if( strcmp( *argp, "--exclude" ) == 0 ||
+                 strcmp( *argp, "-x" ) == 0 )
+        {
+            exclude_mode = 1;
+        }
+        else
+            break;
     }
-    else
-    {
-        v = 1;
+
+    if( v != 0 )
         mbedtls_printf( "\n" );
-    }
 
 #if defined(MBEDTLS_SELF_TEST)
 
@@ -182,246 +318,60 @@ int main( int argc, char *argv[] )
     mbedtls_memory_buffer_alloc_init( buf, sizeof(buf) );
 #endif
 
-#if defined(MBEDTLS_MD2_C)
-    if( mbedtls_md2_self_test( v )  != 0 )
+    if( *argp != NULL && exclude_mode == 0 )
     {
-        suites_failed++;
+        /* Run the specified tests */
+        for( ; *argp != NULL; argp++ )
+        {
+            for( test = selftests; test->name != NULL; test++ )
+            {
+                if( !strcmp( *argp, test->name ) )
+                {
+                    if( test->function( v )  != 0 )
+                    {
+                        suites_failed++;
+                    }
+                    suites_tested++;
+                    break;
+                }
+            }
+            if( test->name == NULL )
+            {
+                mbedtls_printf( "  Test suite %s not available -> failed\n\n", *argp );
+                suites_failed++;
+            }
+        }
     }
-    suites_tested++;
-#endif
-
-#if defined(MBEDTLS_MD4_C)
-    if( mbedtls_md4_self_test( v ) != 0 )
+    else
     {
-        suites_failed++;
+        /* Run all the tests except excluded ones */
+        for( test = selftests; test->name != NULL; test++ )
+        {
+            if( exclude_mode )
+            {
+                char **excluded;
+                for( excluded = argp; *excluded != NULL; ++excluded )
+                {
+                    if( !strcmp( *excluded, test->name ) )
+                        break;
+                }
+                if( *excluded )
+                {
+                    if( v )
+                        mbedtls_printf( "  Skip: %s\n", test->name );
+                    continue;
+                }
+            }
+            if( test->function( v )  != 0 )
+            {
+                suites_failed++;
+            }
+            suites_tested++;
+        }
     }
-    suites_tested++;
-#endif
-
-#if defined(MBEDTLS_MD5_C)
-    if( mbedtls_md5_self_test( v ) != 0 )
-    {
-        suites_failed++;
-    }
-    suites_tested++;
-#endif
-
-#if defined(MBEDTLS_RIPEMD160_C)
-    if( mbedtls_ripemd160_self_test( v ) != 0 )
-    {
-        suites_failed++;
-    }
-    suites_tested++;
-#endif
-
-#if defined(MBEDTLS_SHA1_C)
-    if( mbedtls_sha1_self_test( v ) != 0 )
-    {
-        suites_failed++;
-    }
-    suites_tested++;
-#endif
-
-#if defined(MBEDTLS_SHA256_C)
-    if( mbedtls_sha256_self_test( v ) != 0 )
-    {
-        suites_failed++;
-    }
-    suites_tested++;
-#endif
-
-#if defined(MBEDTLS_SHA512_C)
-    if( mbedtls_sha512_self_test( v ) != 0 )
-    {
-        suites_failed++;
-    }
-    suites_tested++;
-#endif
-
-#if defined(MBEDTLS_ARC4_C)
-    if( mbedtls_arc4_self_test( v ) != 0 )
-    {
-        suites_failed++;
-    }
-    suites_tested++;
-#endif
-
-#if defined(MBEDTLS_DES_C)
-    if( mbedtls_des_self_test( v ) != 0 )
-    {
-        suites_failed++;
-    }
-    suites_tested++;
-#endif
-
-#if defined(MBEDTLS_AES_C)
-    if( mbedtls_aes_self_test( v ) != 0 )
-    {
-        suites_failed++;
-    }
-    suites_tested++;
-#endif
-
-#if defined(MBEDTLS_GCM_C) && defined(MBEDTLS_AES_C)
-    if( mbedtls_gcm_self_test( v ) != 0 )
-    {
-        suites_failed++;
-    }
-    suites_tested++;
-#endif
-
-#if defined(MBEDTLS_CCM_C) && defined(MBEDTLS_AES_C)
-    if( mbedtls_ccm_self_test( v ) != 0 )
-    {
-        suites_failed++;
-    }
-    suites_tested++;
-#endif
-
-#if defined(MBEDTLS_CMAC_C)
-    if( ( mbedtls_cmac_self_test( v ) ) != 0 )
-    {
-        suites_failed++;
-    }
-    suites_tested++;
-#endif
-
-#if defined(MBEDTLS_BASE64_C)
-    if( mbedtls_base64_self_test( v ) != 0 )
-    {
-        suites_failed++;
-    }
-    suites_tested++;
-#endif
-
-#if defined(MBEDTLS_BIGNUM_C)
-    if( mbedtls_mpi_self_test( v ) != 0 )
-    {
-        suites_failed++;
-    }
-    suites_tested++;
-#endif
-
-#if defined(MBEDTLS_RSA_C)
-    if( mbedtls_rsa_self_test( v ) != 0 )
-    {
-        suites_failed++;
-    }
-    suites_tested++;
-#endif
-
-#if defined(MBEDTLS_X509_USE_C)
-    if( mbedtls_x509_self_test( v ) != 0 )
-    {
-        suites_failed++;
-    }
-    suites_tested++;
-#endif
-
-#if defined(MBEDTLS_XTEA_C)
-    if( mbedtls_xtea_self_test( v ) != 0 )
-    {
-        suites_failed++;
-    }
-    suites_tested++;
-#endif
-
-#if defined(MBEDTLS_CAMELLIA_C)
-    if( mbedtls_camellia_self_test( v ) != 0 )
-    {
-        suites_failed++;
-    }
-    suites_tested++;
-#endif
-
-#if defined(MBEDTLS_CTR_DRBG_C)
-    if( mbedtls_ctr_drbg_self_test( v ) != 0 )
-    {
-        suites_failed++;
-    }
-    suites_tested++;
-#endif
-
-#if defined(MBEDTLS_HMAC_DRBG_C)
-    if( mbedtls_hmac_drbg_self_test( v ) != 0 )
-    {
-        suites_failed++;
-    }
-    suites_tested++;
-#endif
-
-#if defined(MBEDTLS_ECP_C)
-    if( mbedtls_ecp_self_test( v ) != 0 )
-    {
-        suites_failed++;
-    }
-    suites_tested++;
-#endif
-
-#if defined(MBEDTLS_ECJPAKE_C)
-    if( mbedtls_ecjpake_self_test( v ) != 0 )
-    {
-        suites_failed++;
-    }
-    suites_tested++;
-#endif
-
-#if defined(MBEDTLS_DHM_C)
-    if( mbedtls_dhm_self_test( v ) != 0 )
-    {
-        suites_failed++;
-    }
-    suites_tested++;
-#endif
-
-#if defined(MBEDTLS_ENTROPY_C)
-
-#if defined(MBEDTLS_ENTROPY_NV_SEED) && !defined(MBEDTLS_NO_PLATFORM_ENTROPY)
-    create_entropy_seed_file();
-#endif
-
-    if( mbedtls_entropy_self_test( v ) != 0 )
-    {
-        suites_failed++;
-    }
-    suites_tested++;
-#endif
-
-#if defined(MBEDTLS_PKCS5_C)
-    if( mbedtls_pkcs5_self_test( v ) != 0 )
-    {
-        suites_failed++;
-    }
-    suites_tested++;
-#endif
-
-/* Slow tests last */
-
-#if defined(MBEDTLS_TIMING_C)
-    if( mbedtls_timing_self_test( v ) != 0 )
-    {
-        suites_failed++;
-    }
-    suites_tested++;
-#endif
-
-    if( v != 0 )
-    {
-#if defined(MBEDTLS_MEMORY_BUFFER_ALLOC_C) && defined(MBEDTLS_MEMORY_DEBUG)
-        mbedtls_memory_buffer_alloc_status();
-#endif
-    }
-
-#if defined(MBEDTLS_MEMORY_BUFFER_ALLOC_C)
-    mbedtls_memory_buffer_alloc_free();
-    if( mbedtls_memory_buffer_alloc_self_test( v ) != 0 )
-    {
-        suites_failed++;
-    }
-    suites_tested++;
-#endif
 
 #else
+    (void) exclude_mode;
     mbedtls_printf( " MBEDTLS_SELF_TEST not defined.\n" );
 #endif
 
diff --git a/scripts/config.pl b/scripts/config.pl
index 5a06a3338..76ca4709c 100755
--- a/scripts/config.pl
+++ b/scripts/config.pl
@@ -45,7 +45,7 @@ my $config_file = "include/mbedtls/config.h";
 my $usage = <<EOU;
 $0 [-f <file> | --file <file>] [-o | --force]
                    [set <symbol> <value> | unset <symbol> | get <symbol> |
-                        full | realfull]
+                        full | realfull | baremetal]
 
 Commands
     set <symbol> [<value>]  - Uncomments or adds a #define for the <symbol> to
@@ -63,6 +63,7 @@ Commands
                               excluding some reserved symbols, until the
                               'Module configuration options' section
     realfull                - Uncomments all #define's with no exclusions
+    baremetal               - Sets full configuration suitable for baremetal build.
 
 Options
     -f | --file <filename>  - The file or file path for the configuration file
@@ -91,14 +92,38 @@ MBEDTLS_X509_ALLOW_EXTENSIONS_NON_V3
 MBEDTLS_X509_ALLOW_UNSUPPORTED_CRITICAL_EXTENSION
 MBEDTLS_ZLIB_SUPPORT
 MBEDTLS_PKCS11_C
+MBEDTLS_NO_UDBL_DIVISION
 _ALT\s*$
 );
 
+# Things that should be disabled in "baremetal"
+my @excluded_baremetal = qw(
+MBEDTLS_NET_C
+MBEDTLS_TIMING_C
+MBEDTLS_FS_IO
+MBEDTLS_ENTROPY_NV_SEED
+MBEDTLS_HAVE_TIME
+MBEDTLS_HAVE_TIME_DATE
+MBEDTLS_DEPRECATED_WARNING
+MBEDTLS_HAVEGE_C
+MBEDTLS_THREADING_C
+MBEDTLS_THREADING_PTHREAD
+MBEDTLS_MEMORY_BACKTRACE
+MBEDTLS_MEMORY_BUFFER_ALLOC_C
+MBEDTLS_PLATFORM_TIME_ALT
+MBEDTLS_PLATFORM_FPRINTF_ALT
+);
+
 # Things that should be enabled in "full" even if they match @excluded
 my @non_excluded = qw(
 PLATFORM_[A-Z0-9]+_ALT
 );
 
+# Things that should be enabled in "baremetal"
+my @non_excluded_baremetal = qw(
+MBEDTLS_NO_PLATFORM_ENTROPY
+);
+
 # Process the command line arguments
 
 my $force_option = 0;
@@ -123,7 +148,7 @@ while ($arg = shift) {
         # ...else assume it's a command
         $action = $arg;
 
-        if ($action eq "full" || $action eq "realfull") {
+        if ($action eq "full" || $action eq "realfull" || $action eq "baremetal" ) {
             # No additional parameters
             die $usage if @ARGV;
 
@@ -166,7 +191,12 @@ open my $config_read, '<', $config_file or die "read $config_file: $!\n";
 my @config_lines = <$config_read>;
 close $config_read;
 
-my ($exclude_re, $no_exclude_re);
+# Add required baremetal symbols to the list that is included.
+if ( $action eq "baremetal" ) {
+    @non_excluded = ( @non_excluded, @non_excluded_baremetal );
+}
+
+my ($exclude_re, $no_exclude_re, $exclude_baremetal_re);
 if ($action eq "realfull") {
     $exclude_re = qr/^$/;
     $no_exclude_re = qr/./;
@@ -174,6 +204,9 @@ if ($action eq "realfull") {
     $exclude_re = join '|', @excluded;
     $no_exclude_re = join '|', @non_excluded;
 }
+if ( $action eq "baremetal" ) {
+    $exclude_baremetal_re = join '|', @excluded_baremetal;
+}
 
 my $config_write = undef;
 if ($action ne "get") {
@@ -182,17 +215,19 @@ if ($action ne "get") {
 
 my $done;
 for my $line (@config_lines) {
-    if ($action eq "full" || $action eq "realfull") {
+    if ($action eq "full" || $action eq "realfull" || $action eq "baremetal" ) {
         if ($line =~ /name SECTION: Module configuration options/) {
             $done = 1;
         }
 
         if (!$done && $line =~ m!^//\s?#define! &&
-                ( $line !~ /$exclude_re/ || $line =~ /$no_exclude_re/ ) ) {
+                ( $line !~ /$exclude_re/ || $line =~ /$no_exclude_re/ ) &&
+                ( $action ne "baremetal" || ( $line !~ /$exclude_baremetal_re/ ) ) ) {
             $line =~ s!^//\s?!!;
         }
         if (!$done && $line =~ m!^\s?#define! &&
-                ! ( $line !~ /$exclude_re/ || $line =~ /$no_exclude_re/ ) ) {
+                ! ( ( $line !~ /$exclude_re/ || $line =~ /$no_exclude_re/ ) &&
+                    ( $action ne "baremetal" || ( $line !~ /$exclude_baremetal_re/ ) ) ) ) {
             $line =~ s!^!//!;
         }
     } elsif ($action eq "unset") {
diff --git a/tests/scripts/all.sh b/tests/scripts/all.sh
index cfe305ffd..6ffd38687 100755
--- a/tests/scripts/all.sh
+++ b/tests/scripts/all.sh
@@ -4,20 +4,78 @@
 #
 # This file is part of mbed TLS (https://tls.mbed.org)
 #
-# Copyright (c) 2014-2016, ARM Limited, All Rights Reserved
-#
+# Copyright (c) 2014-2017, ARM Limited, All Rights Reserved
+
+
+
+################################################################
+#### Documentation
+################################################################
+
 # Purpose
+# -------
 #
 # To run all tests possible or available on the platform.
 #
+# Notes for users
+# ---------------
+#
 # Warning: the test is destructive. It includes various build modes and
 # configurations, and can and will arbitrarily change the current CMake
-# configuration. After this script has been run, the CMake cache will be lost
-# and CMake will no longer be initialised.
+# configuration. The following files must be committed into git:
+#    * include/mbedtls/config.h
+#    * Makefile, library/Makefile, programs/Makefile, tests/Makefile
+# After running this script, the CMake cache will be lost and CMake
+# will no longer be initialised.
 #
-# The script assumes the presence of gcc and clang (recent enough for using
-# ASan with gcc and MemSan with clang, or valgrind) are available, as well as
-# cmake and a "good" find.
+# The script assumes the presence of a number of tools:
+#   * Basic Unix tools (Windows users note: a Unix-style find must be before
+#     the Windows find in the PATH)
+#   * Perl
+#   * GNU Make
+#   * CMake
+#   * GCC and Clang (recent enough for using ASan with gcc and MemSan with clang, or valgrind)
+#   * arm-gcc and mingw-gcc
+#   * ArmCC 5 and ArmCC 6, unless invoked with --no-armcc
+#   * Yotta build dependencies, unless invoked with --no-yotta
+#   * OpenSSL and GnuTLS command line tools, recent enough for the
+#     interoperability tests. If they don't support SSLv3 then a legacy
+#     version of these tools must be present as well (search for LEGACY
+#     below).
+# See the invocation of check_tools below for details.
+#
+# This script must be invoked from the toplevel directory of a git
+# working copy of Mbed TLS.
+#
+# Note that the output is not saved. You may want to run
+#   script -c tests/scripts/all.sh
+# or
+#   tests/scripts/all.sh >all.log 2>&1
+#
+# Notes for maintainers
+# ---------------------
+#
+# The tests are roughly in order from fastest to slowest. This doesn't
+# have to be exact, but in general you should add slower tests towards
+# the end and fast checks near the beginning.
+#
+# Sanity checks have the following form:
+#   1. msg "short description of what is about to be done"
+#   2. run sanity check (failure stops the script)
+#
+# Build or build-and-test steps have the following form:
+#   1. msg "short description of what is about to be done"
+#   2. cleanup
+#   3. preparation (config.pl, cmake, ...) (failure stops the script)
+#   4. make
+#   5. Run tests if relevant. All tests must be prefixed with
+#      if_build_successful for the sake of --keep-going.
+
+
+
+################################################################
+#### Initialization and command line parsing
+################################################################
 
 # Abort on errors (and uninitialised variables)
 set -eu
@@ -35,7 +93,9 @@ CONFIG_BAK="$CONFIG_H.bak"
 
 MEMORY=0
 FORCE=0
+KEEP_GOING=0
 RELEASE=0
+RUN_ARMCC=1
 YOTTA=1
 
 # Default commands, can be overriden by the environment
@@ -56,28 +116,38 @@ fi
 
 usage()
 {
-    printf "Usage: $0\n"
-    printf "  -h|--help\t\tPrint this help.\n"
-    printf "  -m|--memory\t\tAdditional optional memory tests.\n"
-    printf "  -f|--force\t\tForce the tests to overwrite any modified files.\n"
-    printf "  -s|--seed\t\tInteger seed value to use for this test run.\n"
-    printf "  -r|--release-test\t\tRun this script in release mode. This fixes the seed value to 1.\n"
-    printf "     --no-yotta\t\tSkip yotta build\n"
-    printf "     --out-of-source-dir=<path>\t\tDirectory used for CMake out-of-source build tests."
-    printf "     --openssl=<OpenSSL_path>\t\tPath to OpenSSL executable to use for most tests.\n"
-    printf "     --openssl-legacy=<OpenSSL_path>\t\tPath to OpenSSL executable to use for legacy tests e.g. SSLv3.\n"
-    printf "     --gnutls-cli=<GnuTLS_cli_path>\t\tPath to GnuTLS client executable to use for most tests.\n"
-    printf "     --gnutls-serv=<GnuTLS_serv_path>\t\tPath to GnuTLS server executable to use for most tests.\n"
-    printf "     --gnutls-legacy-cli=<GnuTLS_cli_path>\t\tPath to GnuTLS client executable to use for legacy tests.\n"
-    printf "     --gnutls-legacy-serv=<GnuTLS_serv_path>\t\tPath to GnuTLS server executable to use for legacy tests.\n"
-    printf "     --armc5-bin-dir=<ARMC5_bin_dir_path>\t\tPath to the ARM Compiler 5 bin directory.\n"
-    printf "     --armc6-bin-dir=<ARMC6_bin_dir_path>\t\tPath to the ARM Compiler 6 bin directory.\n"
+    cat <<EOF
+Usage: $0 [OPTION]...
+  -h|--help             Print this help.
+
+General options:
+  -f|--force            Force the tests to overwrite any modified files.
+  -k|--keep-going       Run all tests and report errors at the end.
+  -m|--memory           Additional optional memory tests.
+     --armcc            Run ARM Compiler builds (on by default).
+     --no-armcc         Skip ARM Compiler builds.
+     --no-yotta         Skip yotta module build.
+     --out-of-source-dir=<path>  Directory used for CMake out-of-source build tests.
+  -r|--release-test     Run this script in release mode. This fixes the seed value to 1.
+  -s|--seed             Integer seed value to use for this test run.
+     --yotta            Build yotta module (on by default).
+
+Tool path options:
+     --armc5-bin-dir=<ARMC5_bin_dir_path>       ARM Compiler 5 bin directory.
+     --armc6-bin-dir=<ARMC6_bin_dir_path>       ARM Compiler 6 bin directory.
+     --gnutls-cli=<GnuTLS_cli_path>             GnuTLS client executable to use for most tests.
+     --gnutls-serv=<GnuTLS_serv_path>           GnuTLS server executable to use for most tests.
+     --gnutls-legacy-cli=<GnuTLS_cli_path>      GnuTLS client executable to use for legacy tests.
+     --gnutls-legacy-serv=<GnuTLS_serv_path>    GnuTLS server executable to use for legacy tests.
+     --openssl=<OpenSSL_path>                   OpenSSL executable to use for most tests.
+     --openssl-legacy=<OpenSSL_path>            OpenSSL executable to use for legacy tests e.g. SSLv3.
+EOF
 }
 
 # remove built files as well as the cmake cache/config
 cleanup()
 {
-    make clean
+    command make clean
 
     find . -name yotta -prune -o -iname '*cmake*' -not -name CMakeLists.txt -exec rm -rf {} \+
     rm -f include/Makefile include/mbedtls/Makefile programs/*/Makefile
@@ -89,7 +159,21 @@ cleanup()
     fi
 }
 
-trap cleanup INT TERM HUP
+# Executed on exit. May be redefined depending on command line options.
+final_report () {
+    :
+}
+
+fatal_signal () {
+    cleanup
+    final_report $1
+    trap - $1
+    kill -$1 $$
+}
+
+trap 'fatal_signal HUP' HUP
+trap 'fatal_signal INT' INT
+trap 'fatal_signal TERM' TERM
 
 msg()
 {
@@ -98,17 +182,20 @@ msg()
     echo "* $1 "
     printf "* "; date
     echo "******************************************************************"
+    current_section=$1
 }
 
-armc6_build_test()
-{
-    FLAGS="$1"
+if [ $RUN_ARMCC -ne 0 ]; then
+    armc6_build_test()
+    {
+        FLAGS="$1"
 
-    msg "build: ARM Compiler 6 ($FLAGS), make"
-    ARM_TOOL_VARIANT="ult" CC="$ARMC6_CC" AR="$ARMC6_AR" CFLAGS="$FLAGS" \
-        WARNING_CFLAGS='-xc -std=c99' make lib
-    make clean
-}
+        msg "build: ARM Compiler 6 ($FLAGS), make"
+        ARM_TOOL_VARIANT="ult" CC="$ARMC6_CC" AR="$ARMC6_AR" CFLAGS="$FLAGS" \
+                        WARNING_CFLAGS='-xc -std=c99' make lib
+        make clean
+    }
+fi
 
 err_msg()
 {
@@ -127,49 +214,8 @@ check_tools()
 
 while [ $# -gt 0 ]; do
     case "$1" in
-        --memory|-m*)
-            MEMORY=${1#-m}
-            ;;
-        --force|-f)
-            FORCE=1
-            ;;
-        --seed|-s)
-            shift
-            SEED="$1"
-            ;;
-        --release-test|-r)
-            RELEASE=1
-            ;;
-          --no-yotta)
-            YOTTA=0
-            ;;
-        --out-of-source-dir)
-            shift
-            OUT_OF_SOURCE_DIR="$1"
-            ;;
-        --openssl)
-            shift
-            OPENSSL="$1"
-            ;;
-        --openssl-legacy)
-            shift
-            OPENSSL_LEGACY="$1"
-            ;;
-        --gnutls-cli)
-            shift
-            GNUTLS_CLI="$1"
-            ;;
-        --gnutls-serv)
-            shift
-            GNUTLS_SERV="$1"
-            ;;
-        --gnutls-legacy-cli)
-            shift
-            GNUTLS_LEGACY_CLI="$1"
-            ;;
-        --gnutls-legacy-serv)
-            shift
-            GNUTLS_LEGACY_SERV="$1"
+        --armcc)
+            RUN_ARMCC=1
             ;;
         --armc5-bin-dir)
             shift
@@ -179,9 +225,67 @@ while [ $# -gt 0 ]; do
             shift
             ARMC6_BIN_DIR="$1"
             ;;
-        --help|-h|*)
+        --force|-f)
+            FORCE=1
+            ;;
+        --gnutls-cli)
+            shift
+            GNUTLS_CLI="$1"
+            ;;
+        --gnutls-legacy-cli)
+            shift
+            GNUTLS_LEGACY_CLI="$1"
+            ;;
+        --gnutls-legacy-serv)
+            shift
+            GNUTLS_LEGACY_SERV="$1"
+            ;;
+        --gnutls-serv)
+            shift
+            GNUTLS_SERV="$1"
+            ;;
+        --help|-h)
             usage
-            exit 1
+            exit
+            ;;
+        --keep-going|-k)
+            KEEP_GOING=1
+            ;;
+        --memory|-m)
+            MEMORY=1
+            ;;
+        --no-armcc)
+            RUN_ARMCC=0
+            ;;
+        --no-yotta)
+            YOTTA=0
+            ;;
+        --openssl)
+            shift
+            OPENSSL="$1"
+            ;;
+        --openssl-legacy)
+            shift
+            OPENSSL_LEGACY="$1"
+            ;;
+        --out-of-source-dir)
+            shift
+            OUT_OF_SOURCE_DIR="$1"
+            ;;
+        --release-test|-r)
+            RELEASE=1
+            ;;
+        --seed|-s)
+            shift
+            SEED="$1"
+            ;;
+        --yotta)
+            YOTTA=1
+            ;;
+        *)
+            echo >&2 "Unknown option: $1"
+            echo >&2 "Run $0 --help for usage."
+            exit 120
             ;;
     esac
     shift
@@ -195,7 +299,7 @@ if [ $FORCE -eq 1 ]; then
     cleanup
 else
 
-    if [ $YOTTA -eq 1 ] && [ -d yotta/module ]; then
+    if [ $YOTTA -ne 0 ] && [ -d yotta/module ]; then
         err_msg "Warning - there is an existing yotta module in the directory 'yotta/module'"
         echo "You can either delete your work and retry, or force the test to overwrite the"
         echo "test by rerunning the script as: $0 --force"
@@ -210,7 +314,6 @@ else
     fi
 
     if ! git diff-files --quiet include/mbedtls/config.h; then
-        echo $?
         err_msg "Warning - the configuration file 'include/mbedtls/config.h' has been edited. "
         echo "You can either delete or preserve your work, or force the test by rerunning the"
         echo "script as: $0 --force"
@@ -218,6 +321,71 @@ else
     fi
 fi
 
+build_status=0
+if [ $KEEP_GOING -eq 1 ]; then
+    failure_summary=
+    failure_count=0
+    start_red=
+    end_color=
+    if [ -t 1 ]; then
+        case "$TERM" in
+            *color*|cygwin|linux|rxvt*|screen|[Eex]term*)
+                start_red=$(printf '\033[31m')
+                end_color=$(printf '\033[0m')
+                ;;
+        esac
+    fi
+    record_status () {
+        if "$@"; then
+            last_status=0
+        else
+            last_status=$?
+            text="$current_section: $* -> $last_status"
+            failure_summary="$failure_summary
+$text"
+            failure_count=$((failure_count + 1))
+            echo "${start_red}^^^^$text^^^^${end_color}"
+        fi
+    }
+    make () {
+        case "$*" in
+            *test|*check)
+                if [ $build_status -eq 0 ]; then
+                    record_status command make "$@"
+                else
+                    echo "(skipped because the build failed)"
+                fi
+                ;;
+            *)
+                record_status command make "$@"
+                build_status=$last_status
+                ;;
+        esac
+    }
+    final_report () {
+        if [ $failure_count -gt 0 ]; then
+            echo
+            echo "!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!"
+            echo "${start_red}FAILED: $failure_count${end_color}$failure_summary"
+            echo "!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!"
+        elif [ -z "${1-}" ]; then
+            echo "SUCCESS :)"
+        fi
+        if [ -n "${1-}" ]; then
+            echo "Killed by SIG$1."
+        fi
+    }
+else
+    record_status () {
+        "$@"
+    }
+fi
+if_build_succeeded () {
+    if [ $build_status -eq 0 ]; then
+        record_status "$@"
+    fi
+}
+
 if [ $RELEASE -eq 1 ]; then
     # Fix the seed value to 1 to ensure that the tests are deterministic.
     SEED=1
@@ -252,9 +420,17 @@ export GNUTLS_SERV="$GNUTLS_SERV"
 
 # Make sure the tools we need are available.
 check_tools "$OPENSSL" "$OPENSSL_LEGACY" "$GNUTLS_CLI" "$GNUTLS_SERV" \
-    "$GNUTLS_LEGACY_CLI" "$GNUTLS_LEGACY_SERV" "doxygen" "dot" \
-    "arm-none-eabi-gcc" "$ARMC5_CC" "$ARMC5_AR" "$ARMC6_CC" "$ARMC6_AR" \
-    "i686-w64-mingw32-gcc"
+            "$GNUTLS_LEGACY_CLI" "$GNUTLS_LEGACY_SERV" "doxygen" "dot" \
+            "arm-none-eabi-gcc" "i686-w64-mingw32-gcc"
+if [ $RUN_ARMCC -ne 0 ]; then
+    check_tools "$ARMC5_CC" "$ARMC5_AR" "$ARMC6_CC" "$ARMC6_AR"
+fi
+
+
+
+################################################################
+#### Basic checks
+################################################################
 
 #
 # Test Suites to be executed
@@ -290,12 +466,18 @@ msg "test: doxygen warnings" # ~ 3s
 cleanup
 tests/scripts/doxygen.sh
 
-if [ $YOTTA -ne 0 ]; then
-    # Note - use of yotta is deprecated, and yotta also requires armcc to be
-    # on the path, and uses whatever version of armcc it finds there.
+
+
+################################################################
+#### Build and test many configurations and targets
+################################################################
+
+if [ $RUN_ARMCC -ne 0 ] && [ $YOTTA -ne 0 ]; then
+    # Note - use of yotta is deprecated, and yotta also requires armcc to be on the
+    # path, and uses whatever version of armcc it finds there.
     msg "build: create and build yotta module" # ~ 30s
     cleanup
-    tests/scripts/yotta-build.sh
+    record_status tests/scripts/yotta-build.sh
 fi
 
 msg "build: cmake, gcc, ASan" # ~ 1 min 50s
@@ -307,16 +489,16 @@ msg "test: main suites (inc. selftests) (ASan build)" # ~ 50s
 make test
 
 msg "test: ssl-opt.sh (ASan build)" # ~ 1 min
-tests/ssl-opt.sh
+if_build_succeeded tests/ssl-opt.sh
 
 msg "test/build: ref-configs (ASan build)" # ~ 6 min 20s
-tests/scripts/test-ref-configs.pl
+if_build_succeeded tests/scripts/test-ref-configs.pl
 
 msg "build: with ASan (rebuild after ref-configs)" # ~ 1 min
 make
 
 msg "test: compat.sh (ASan build)" # ~ 6 min
-tests/compat.sh
+if_build_succeeded tests/compat.sh
 
 msg "build: Default + SSLv3 (ASan build)" # ~ 6 min
 cleanup
@@ -329,11 +511,11 @@ msg "test: SSLv3 - main suites (inc. selftests) (ASan build)" # ~ 50s
 make test
 
 msg "build: SSLv3 - compat.sh (ASan build)" # ~ 6 min
-tests/compat.sh -m 'tls1 tls1_1 tls1_2 dtls1 dtls1_2'
-OPENSSL_CMD="$OPENSSL_LEGACY" tests/compat.sh -m 'ssl3'
+if_build_succeeded tests/compat.sh -m 'tls1 tls1_1 tls1_2 dtls1 dtls1_2'
+if_build_succeeded env OPENSSL_CMD="$OPENSSL_LEGACY" tests/compat.sh -m 'ssl3'
 
 msg "build: SSLv3 - ssl-opt.sh (ASan build)" # ~ 6 min
-tests/ssl-opt.sh
+if_build_succeeded tests/ssl-opt.sh
 
 msg "build: Default + !MBEDTLS_SSL_RENEGOTIATION (ASan build)" # ~ 6 min
 cleanup
@@ -346,7 +528,7 @@ msg "test: !MBEDTLS_SSL_RENEGOTIATION - main suites (inc. selftests) (ASan build
 make test
 
 msg "test: !MBEDTLS_SSL_RENEGOTIATION - ssl-opt.sh (ASan build)" # ~ 6 min
-tests/ssl-opt.sh
+if_build_succeeded tests/ssl-opt.sh
 
 msg "build: cmake, full config, clang, C99" # ~ 50s
 cleanup
@@ -354,30 +536,30 @@ cp "$CONFIG_H" "$CONFIG_BAK"
 scripts/config.pl full
 scripts/config.pl unset MBEDTLS_MEMORY_BACKTRACE # too slow for tests
 CC=clang cmake -D CMAKE_BUILD_TYPE:String=Check -D ENABLE_TESTING=On .
-CFLAGS='-Werror -Wall -Wextra -std=c99 -pedantic' make
+make CFLAGS='-Werror -Wall -Wextra -std=c99 -pedantic'
 
 msg "test: main suites (full config)" # ~ 5s
-CFLAGS='-Werror -Wall -Wextra' make test
+make CFLAGS='-Werror -Wall -Wextra' test
 
 msg "test: ssl-opt.sh default (full config)" # ~ 1s
-tests/ssl-opt.sh -f Default
+if_build_succeeded tests/ssl-opt.sh -f Default
 
 msg "test: compat.sh RC4, DES & NULL (full config)" # ~ 2 min
-OPENSSL_CMD="$OPENSSL_LEGACY" GNUTLS_CLI="$GNUTLS_LEGACY_CLI" GNUTLS_SERV="$GNUTLS_LEGACY_SERV" tests/compat.sh -e '3DES\|DES-CBC3' -f 'NULL\|DES\|RC4\|ARCFOUR'
+if_build_succeeded env OPENSSL_CMD="$OPENSSL_LEGACY" GNUTLS_CLI="$GNUTLS_LEGACY_CLI" GNUTLS_SERV="$GNUTLS_LEGACY_SERV" tests/compat.sh -e '3DES\|DES-CBC3' -f 'NULL\|DES\|RC4\|ARCFOUR'
 
 msg "test/build: curves.pl (gcc)" # ~ 4 min
 cleanup
 cmake -D CMAKE_BUILD_TYPE:String=Debug .
-tests/scripts/curves.pl
+if_build_succeeded tests/scripts/curves.pl
 
 msg "test/build: key-exchanges (gcc)" # ~ 1 min
 cleanup
 cmake -D CMAKE_BUILD_TYPE:String=Check .
-tests/scripts/key-exchanges.pl
+if_build_succeeded tests/scripts/key-exchanges.pl
 
 msg "build: Unix make, -Os (gcc)" # ~ 30s
 cleanup
-CC=gcc CFLAGS='-Werror -Wall -Wextra -Os' make
+make CC=gcc CFLAGS='-Werror -Wall -Wextra -Os'
 
 # Full configuration build, without platform support, file IO and net sockets.
 # This should catch missing mbedtls_printf definitions, and by disabling file
@@ -399,8 +581,8 @@ scripts/config.pl unset MBEDTLS_MEMORY_BUFFER_ALLOC_C
 scripts/config.pl unset MBEDTLS_FS_IO
 # Note, _DEFAULT_SOURCE needs to be defined for platforms using glibc version >2.19,
 # to re-enable platform integration features otherwise disabled in C99 builds
-CC=gcc CFLAGS='-Werror -Wall -Wextra -std=c99 -pedantic -O0 -D_DEFAULT_SOURCE' make lib programs
-CC=gcc CFLAGS='-Werror -Wall -Wextra -O0' make test
+make CC=gcc CFLAGS='-Werror -Wall -Wextra -std=c99 -pedantic -O0 -D_DEFAULT_SOURCE' lib programs
+make CC=gcc CFLAGS='-Werror -Wall -Wextra -O0' test
 
 # catch compile bugs in _uninit functions
 msg "build: full config with NO_STD_FUNCTION, make, gcc" # ~ 30s
@@ -409,21 +591,21 @@ cp "$CONFIG_H" "$CONFIG_BAK"
 scripts/config.pl full
 scripts/config.pl set MBEDTLS_PLATFORM_NO_STD_FUNCTIONS
 scripts/config.pl unset MBEDTLS_ENTROPY_NV_SEED
-CC=gcc CFLAGS='-Werror -Wall -Wextra -O0' make
+make CC=gcc CFLAGS='-Werror -Wall -Wextra -O0'
 
 msg "build: full config except ssl_srv.c, make, gcc" # ~ 30s
 cleanup
 cp "$CONFIG_H" "$CONFIG_BAK"
 scripts/config.pl full
 scripts/config.pl unset MBEDTLS_SSL_SRV_C
-CC=gcc CFLAGS='-Werror -Wall -Wextra -O0' make
+make CC=gcc CFLAGS='-Werror -Wall -Wextra -O0'
 
 msg "build: full config except ssl_cli.c, make, gcc" # ~ 30s
 cleanup
 cp "$CONFIG_H" "$CONFIG_BAK"
 scripts/config.pl full
 scripts/config.pl unset MBEDTLS_SSL_CLI_C
-CC=gcc CFLAGS='-Werror -Wall -Werror -O0' make
+make CC=gcc CFLAGS='-Werror -Wall -Werror -O0'
 
 # Note, C99 compliance can also be tested with the sockets support disabled,
 # as that requires a POSIX platform (which isn't the same as C99).
@@ -433,7 +615,7 @@ cp "$CONFIG_H" "$CONFIG_BAK"
 scripts/config.pl full
 scripts/config.pl unset MBEDTLS_NET_C # getaddrinfo() undeclared, etc.
 scripts/config.pl set MBEDTLS_NO_PLATFORM_ENTROPY # uses syscall() on GNU/Linux
-CC=gcc CFLAGS='-Werror -Wall -Wextra -O0 -std=c99 -pedantic' make lib
+make CC=gcc CFLAGS='-Werror -Wall -Wextra -O0 -std=c99 -pedantic' lib
 
 msg "build: default config except MFL extension (ASan build)" # ~ 30s
 cleanup
@@ -443,7 +625,7 @@ CC=gcc cmake -D CMAKE_BUILD_TYPE:String=Asan .
 make
 
 msg "test: ssl-opt.sh, MFL-related tests"
-tests/ssl-opt.sh -f "Max fragment length"
+if_build_succeeded tests/ssl-opt.sh -f "Max fragment length"
 
 msg "build: default config with  MBEDTLS_TEST_NULL_ENTROPY (ASan build)"
 cleanup
@@ -461,42 +643,42 @@ msg "test: MBEDTLS_TEST_NULL_ENTROPY - main suites (inc. selftests) (ASan build)
 make test
 
 if uname -a | grep -F Linux >/dev/null; then
-msg "build/test: make shared" # ~ 40s
-cleanup
-make SHARED=1 all check
+    msg "build/test: make shared" # ~ 40s
+    cleanup
+    make SHARED=1 all check
 fi
 
 if uname -a | grep -F x86_64 >/dev/null; then
-msg "build: i386, make, gcc" # ~ 30s
-cleanup
-CC=gcc CFLAGS='-Werror -Wall -Wextra -m32' make
+    msg "build: i386, make, gcc" # ~ 30s
+    cleanup
+    make CC=gcc CFLAGS='-Werror -Wall -Wextra -m32'
 
-msg "build: gcc, force 32-bit compilation"
-cleanup
-cp "$CONFIG_H" "$CONFIG_BAK"
-scripts/config.pl unset MBEDTLS_HAVE_ASM
-scripts/config.pl unset MBEDTLS_AESNI_C
-scripts/config.pl unset MBEDTLS_PADLOCK_C
-CC=gcc CFLAGS='-Werror -Wall -Wextra -DMBEDTLS_HAVE_INT32' make
+    msg "build: gcc, force 32-bit compilation"
+    cleanup
+    cp "$CONFIG_H" "$CONFIG_BAK"
+    scripts/config.pl unset MBEDTLS_HAVE_ASM
+    scripts/config.pl unset MBEDTLS_AESNI_C
+    scripts/config.pl unset MBEDTLS_PADLOCK_C
+    make CC=gcc CFLAGS='-Werror -Wall -Wextra -DMBEDTLS_HAVE_INT32'
 
-msg "build: gcc, force 64-bit compilation"
-cleanup
-cp "$CONFIG_H" "$CONFIG_BAK"
-scripts/config.pl unset MBEDTLS_HAVE_ASM
-scripts/config.pl unset MBEDTLS_AESNI_C
-scripts/config.pl unset MBEDTLS_PADLOCK_C
-CC=gcc CFLAGS='-Werror -Wall -Wextra -DMBEDTLS_HAVE_INT64' make
+    msg "build: gcc, force 64-bit compilation"
+    cleanup
+    cp "$CONFIG_H" "$CONFIG_BAK"
+    scripts/config.pl unset MBEDTLS_HAVE_ASM
+    scripts/config.pl unset MBEDTLS_AESNI_C
+    scripts/config.pl unset MBEDTLS_PADLOCK_C
+    make CC=gcc CFLAGS='-Werror -Wall -Wextra -DMBEDTLS_HAVE_INT64'
 
-msg "test: gcc, force 64-bit compilation"
-make test
+    msg "test: gcc, force 64-bit compilation"
+    make test
 
-msg "build: gcc, force 64-bit compilation"
-cleanup
-cp "$CONFIG_H" "$CONFIG_BAK"
-scripts/config.pl unset MBEDTLS_HAVE_ASM
-scripts/config.pl unset MBEDTLS_AESNI_C
-scripts/config.pl unset MBEDTLS_PADLOCK_C
-CC=gcc CFLAGS='-Werror -Wall -Wextra -DMBEDTLS_HAVE_INT64' make
+    msg "build: gcc, force 64-bit compilation"
+    cleanup
+    cp "$CONFIG_H" "$CONFIG_BAK"
+    scripts/config.pl unset MBEDTLS_HAVE_ASM
+    scripts/config.pl unset MBEDTLS_AESNI_C
+    scripts/config.pl unset MBEDTLS_PADLOCK_C
+    make CC=gcc CFLAGS='-Werror -Wall -Wextra -DMBEDTLS_HAVE_INT64'
 fi # x86_64
 
 msg "build: arm-none-eabi-gcc, make" # ~ 10s
@@ -514,7 +696,7 @@ scripts/config.pl unset MBEDTLS_THREADING_PTHREAD
 scripts/config.pl unset MBEDTLS_THREADING_C
 scripts/config.pl unset MBEDTLS_MEMORY_BACKTRACE # execinfo.h
 scripts/config.pl unset MBEDTLS_MEMORY_BUFFER_ALLOC_C # calls exit
-CC=arm-none-eabi-gcc AR=arm-none-eabi-ar LD=arm-none-eabi-ld CFLAGS='-Werror -Wall -Wextra' make lib
+make CC=arm-none-eabi-gcc AR=arm-none-eabi-ar LD=arm-none-eabi-ld CFLAGS='-Werror -Wall -Wextra' lib
 
 msg "build: arm-none-eabi-gcc -DMBEDTLS_NO_UDBL_DIVISION, make" # ~ 10s
 cleanup
@@ -532,7 +714,7 @@ scripts/config.pl unset MBEDTLS_THREADING_C
 scripts/config.pl unset MBEDTLS_MEMORY_BACKTRACE # execinfo.h
 scripts/config.pl unset MBEDTLS_MEMORY_BUFFER_ALLOC_C # calls exit
 scripts/config.pl set MBEDTLS_NO_UDBL_DIVISION
-CC=arm-none-eabi-gcc AR=arm-none-eabi-ar LD=arm-none-eabi-ld CFLAGS='-Werror -Wall -Wextra' make lib
+make CC=arm-none-eabi-gcc AR=arm-none-eabi-ar LD=arm-none-eabi-ld CFLAGS='-Werror -Wall -Wextra' lib
 echo "Checking that software 64-bit division is not required"
 ! grep __aeabi_uldiv library/*.o
 
@@ -556,32 +738,34 @@ scripts/config.pl unset MBEDTLS_MEMORY_BACKTRACE # execinfo.h
 scripts/config.pl unset MBEDTLS_MEMORY_BUFFER_ALLOC_C # calls exit
 scripts/config.pl unset MBEDTLS_PLATFORM_TIME_ALT # depends on MBEDTLS_HAVE_TIME
 
-CC="$ARMC5_CC" AR="$ARMC5_AR" WARNING_CFLAGS='--strict --c99' make lib
-make clean
+if [ $RUN_ARMCC -ne 0 ]; then
+    make CC="$ARMC5_CC" AR="$ARMC5_AR" WARNING_CFLAGS='--strict --c99' lib
+    make clean
 
-# ARM Compiler 6 - Target ARMv7-A
-armc6_build_test "--target=arm-arm-none-eabi -march=armv7-a"
+    # ARM Compiler 6 - Target ARMv7-A
+    armc6_build_test "--target=arm-arm-none-eabi -march=armv7-a"
 
-# ARM Compiler 6 - Target ARMv7-M
-armc6_build_test "--target=arm-arm-none-eabi -march=armv7-m"
+    # ARM Compiler 6 - Target ARMv7-M
+    armc6_build_test "--target=arm-arm-none-eabi -march=armv7-m"
 
-# ARM Compiler 6 - Target ARMv8-A - AArch32
-armc6_build_test "--target=arm-arm-none-eabi -march=armv8.2-a"
+    # ARM Compiler 6 - Target ARMv8-A - AArch32
+    armc6_build_test "--target=arm-arm-none-eabi -march=armv8.2-a"
 
-# ARM Compiler 6 - Target ARMv8-M
-armc6_build_test "--target=arm-arm-none-eabi -march=armv8-m.main"
+    # ARM Compiler 6 - Target ARMv8-M
+    armc6_build_test "--target=arm-arm-none-eabi -march=armv8-m.main"
 
-# ARM Compiler 6 - Target ARMv8-A - AArch64
-armc6_build_test "--target=aarch64-arm-none-eabi -march=armv8.2-a"
+    # ARM Compiler 6 - Target ARMv8-A - AArch64
+    armc6_build_test "--target=aarch64-arm-none-eabi -march=armv8.2-a"
+fi
 
 msg "build: allow SHA1 in certificates by default"
 cleanup
 cp "$CONFIG_H" "$CONFIG_BAK"
 scripts/config.pl set MBEDTLS_TLS_DEFAULT_ALLOW_SHA1_IN_CERTIFICATES
-CFLAGS='-Werror -Wall -Wextra' make
+make CFLAGS='-Werror -Wall -Wextra'
 msg "test: allow SHA1 in certificates by default"
 make test
-tests/ssl-opt.sh -f SHA-1
+if_build_succeeded tests/ssl-opt.sh -f SHA-1
 
 msg "build: default config, MBEDTLS_RSA_NO_CRT, make, gcc"
 cleanup
@@ -594,63 +778,63 @@ make test
 
 msg "build: Windows cross build - mingw64, make (Link Library)" # ~ 30s
 cleanup
-CC=i686-w64-mingw32-gcc AR=i686-w64-mingw32-ar LD=i686-w64-minggw32-ld CFLAGS='-Werror -Wall -Wextra' WINDOWS_BUILD=1 make lib programs
+make CC=i686-w64-mingw32-gcc AR=i686-w64-mingw32-ar LD=i686-w64-minggw32-ld CFLAGS='-Werror -Wall -Wextra' WINDOWS_BUILD=1 lib programs
 
 # note Make tests only builds the tests, but doesn't run them
-CC=i686-w64-mingw32-gcc AR=i686-w64-mingw32-ar LD=i686-w64-minggw32-ld CFLAGS='-Werror' WINDOWS_BUILD=1 make tests
-WINDOWS_BUILD=1 make clean
+make CC=i686-w64-mingw32-gcc AR=i686-w64-mingw32-ar LD=i686-w64-minggw32-ld CFLAGS='-Werror' WINDOWS_BUILD=1 tests
+make WINDOWS_BUILD=1 clean
 
 msg "build: Windows cross build - mingw64, make (DLL)" # ~ 30s
-CC=i686-w64-mingw32-gcc AR=i686-w64-mingw32-ar LD=i686-w64-minggw32-ld CFLAGS='-Werror -Wall -Wextra' WINDOWS_BUILD=1 SHARED=1 make lib programs
-CC=i686-w64-mingw32-gcc AR=i686-w64-mingw32-ar LD=i686-w64-minggw32-ld CFLAGS='-Werror -Wall -Wextra' WINDOWS_BUILD=1 SHARED=1 make tests
-WINDOWS_BUILD=1 make clean
+make CC=i686-w64-mingw32-gcc AR=i686-w64-mingw32-ar LD=i686-w64-minggw32-ld CFLAGS='-Werror -Wall -Wextra' WINDOWS_BUILD=1 SHARED=1 lib programs
+make CC=i686-w64-mingw32-gcc AR=i686-w64-mingw32-ar LD=i686-w64-minggw32-ld CFLAGS='-Werror -Wall -Wextra' WINDOWS_BUILD=1 SHARED=1 tests
+make WINDOWS_BUILD=1 clean
 
 # MemSan currently only available on Linux 64 bits
 if uname -a | grep 'Linux.*x86_64' >/dev/null; then
 
-msg "build: MSan (clang)" # ~ 1 min 20s
-cleanup
-cp "$CONFIG_H" "$CONFIG_BAK"
-scripts/config.pl unset MBEDTLS_AESNI_C # memsan doesn't grok asm
-CC=clang cmake -D CMAKE_BUILD_TYPE:String=MemSan .
-make
+    msg "build: MSan (clang)" # ~ 1 min 20s
+    cleanup
+    cp "$CONFIG_H" "$CONFIG_BAK"
+    scripts/config.pl unset MBEDTLS_AESNI_C # memsan doesn't grok asm
+    CC=clang cmake -D CMAKE_BUILD_TYPE:String=MemSan .
+    make
 
-msg "test: main suites (MSan)" # ~ 10s
-make test
+    msg "test: main suites (MSan)" # ~ 10s
+    make test
 
-msg "test: ssl-opt.sh (MSan)" # ~ 1 min
-tests/ssl-opt.sh
+    msg "test: ssl-opt.sh (MSan)" # ~ 1 min
+    if_build_succeeded tests/ssl-opt.sh
 
-# Optional part(s)
+    # Optional part(s)
 
-if [ "$MEMORY" -gt 0 ]; then
-    msg "test: compat.sh (MSan)" # ~ 6 min 20s
-    tests/compat.sh
-fi
+    if [ "$MEMORY" -gt 0 ]; then
+        msg "test: compat.sh (MSan)" # ~ 6 min 20s
+        if_build_succeeded tests/compat.sh
+    fi
 
 else # no MemSan
 
-msg "build: Release (clang)"
-cleanup
-CC=clang cmake -D CMAKE_BUILD_TYPE:String=Release .
-make
+    msg "build: Release (clang)"
+    cleanup
+    CC=clang cmake -D CMAKE_BUILD_TYPE:String=Release .
+    make
 
-msg "test: main suites valgrind (Release)"
-make memcheck
+    msg "test: main suites valgrind (Release)"
+    make memcheck
 
-# Optional part(s)
-# Currently broken, programs don't seem to receive signals
-# under valgrind on OS X
+    # Optional part(s)
+    # Currently broken, programs don't seem to receive signals
+    # under valgrind on OS X
 
-if [ "$MEMORY" -gt 0 ]; then
-    msg "test: ssl-opt.sh --memcheck (Release)"
-    tests/ssl-opt.sh --memcheck
-fi
+    if [ "$MEMORY" -gt 0 ]; then
+        msg "test: ssl-opt.sh --memcheck (Release)"
+        if_build_succeeded tests/ssl-opt.sh --memcheck
+    fi
 
-if [ "$MEMORY" -gt 1 ]; then
-    msg "test: compat.sh --memcheck (Release)"
-    tests/compat.sh --memcheck
-fi
+    if [ "$MEMORY" -gt 1 ]; then
+        msg "test: compat.sh --memcheck (Release)"
+        if_build_succeeded tests/compat.sh --memcheck
+    fi
 
 fi # MemSan
 
@@ -667,5 +851,13 @@ make test
 cd "$MBEDTLS_ROOT_DIR"
 rm -rf "$OUT_OF_SOURCE_DIR"
 
+
+
+################################################################
+#### Termination
+################################################################
+
 msg "Done, cleaning up"
 cleanup
+
+final_report
diff --git a/tests/suites/test_suite_timing.data b/tests/suites/test_suite_timing.data
index 3ba79a476..4dddcf7fc 100644
--- a/tests/suites/test_suite_timing.data
+++ b/tests/suites/test_suite_timing.data
@@ -1,2 +1,41 @@
-Timing selftest
-timing_selftest:
+Timing: basic timer operation
+timing_timer_simple:
+
+Timing: timer reset
+timing_timer_reset:
+
+Timing: two parallel timers, delay 0
+timing_two_timers:0:
+
+Timing: two parallel timers, delay 100
+timing_two_timers:100:
+
+Timing: two parallel timers, delay 1000
+timing_two_timers:1000:
+
+Timing: two parallel timers, delay 10000
+timing_two_timers:10000:
+
+Timing: delay 0ms, 0ms
+timing_delay:0:0:
+
+Timing: delay 0ms, 50ms
+timing_delay:0:50:
+
+Timing: delay 50ms, 50ms
+timing_delay:50:50:
+
+Timing: delay 50ms, 100ms
+timing_delay:50:100:
+
+Timing: delay 50ms, 200ms
+timing_delay:50:200:
+
+Timing: alarm in 0 second
+timing_alarm:0:
+
+Timing: alarm in 1 second
+timing_alarm:1:
+
+Timing: hardclock
+timing_hardclock:
diff --git a/tests/suites/test_suite_timing.function b/tests/suites/test_suite_timing.function
index 5882f85d7..1610155fb 100644
--- a/tests/suites/test_suite_timing.function
+++ b/tests/suites/test_suite_timing.function
@@ -1,5 +1,51 @@
 /* BEGIN_HEADER */
+
+/* This test module exercises the timing module. One of the expected failure
+   modes is for timers to never expire, which could lead to an infinite loop.
+   The function timing_timer_simple is protected against this failure mode and
+   checks that timers do expire. Other functions will terminate if their
+   timers do expire. Therefore it is recommended to run timing_timer_simple
+   first and run other test functions only if that timing_timer_simple
+   succeeded. */
+
+#include <limits.h>
+
 #include "mbedtls/timing.h"
+
+/* Wait this many milliseconds for a short timing test. This duration
+   should be large enough that, in practice, if you read the timer
+   value twice in a row, it won't have jumped by that much. */
+#define TIMING_SHORT_TEST_MS 100
+
+/* A loop that waits TIMING_SHORT_TEST_MS must not take more than this many
+   iterations. This value needs to be large enough to accommodate fast
+   platforms (e.g. at 4GHz and 10 cycles/iteration a CPU can run through 20
+   million iterations in 50ms). The only motivation to keep this value low is
+   to avoid having an infinite loop if the timer functions are not implemented
+   correctly. Ideally this value should be based on the processor speed but we
+   don't have this information! */
+#define TIMING_SHORT_TEST_ITERATIONS_MAX 1e8
+
+/* alarm(0) must fire in no longer than this amount of time. */
+#define TIMING_ALARM_0_DELAY_MS TIMING_SHORT_TEST_MS
+
+static int expected_delay_status( uint32_t int_ms, uint32_t fin_ms,
+                                  unsigned long actual_ms )
+{
+    return( fin_ms == 0 ? -1 :
+            actual_ms >= fin_ms ? 2 :
+            actual_ms >= int_ms ? 1 :
+            0 );
+}
+
+/* Some conditions in timing_timer_simple suggest that timers are unreliable.
+   Most other test cases rely on timers to terminate, and could loop
+   indefinitely if timers are too broken. So if timing_timer_simple detected a
+   timer that risks not terminating (going backwards, or not reaching the
+   desired count in the alloted clock cycles), set this flag to immediately
+   fail those other tests without running any timers. */
+static int timers_are_badly_broken = 0;
+
 /* END_HEADER */
 
 /* BEGIN_DEPENDENCIES
@@ -7,9 +53,351 @@
  * END_DEPENDENCIES
  */
 
-/* BEGIN_CASE depends_on:MBEDTLS_SELF_TEST */
-void timing_selftest()
+/* BEGIN_CASE */
+void timing_timer_simple( )
 {
-    TEST_ASSERT( mbedtls_timing_self_test( 1 ) == 0 );
+    struct mbedtls_timing_hr_time timer;
+    unsigned long millis = 0;
+    unsigned long new_millis = 0;
+    unsigned long iterations = 0;
+    /* Start the timer. */
+    (void) mbedtls_timing_get_timer( &timer, 1 );
+    /* Busy-wait loop for a few milliseconds. */
+    do
+    {
+        new_millis = mbedtls_timing_get_timer( &timer, 0 );
+        ++iterations;
+        /* Check that the timer didn't go backwards */
+        TEST_ASSERT( new_millis >= millis );
+        millis = new_millis;
+    }
+    while( millis < TIMING_SHORT_TEST_MS &&
+           iterations <= TIMING_SHORT_TEST_ITERATIONS_MAX );
+    /* The wait duration should have been large enough for at least a
+       few runs through the loop, even on the slowest realistic platform. */
+    TEST_ASSERT( iterations >= 2 );
+    /* The wait duration shouldn't have overflowed the iteration count. */
+    TEST_ASSERT( iterations < TIMING_SHORT_TEST_ITERATIONS_MAX );
+    return;
+
+exit:
+    if( iterations >= TIMING_SHORT_TEST_ITERATIONS_MAX ||
+        new_millis < millis )
+    {
+        /* The timer was very unreliable: it didn't increment and the loop ran
+           out, or it went backwards. Other tests that use timers might go
+           into an infinite loop, so we'll skip them. */
+        timers_are_badly_broken = 1;
+    }
+
+    /* No cleanup needed, but show some diagnostic iterations, because timing
+       problems can be hard to reproduce. */
+    mbedtls_fprintf( stdout, "  Finished with millis=%lu new_millis=%lu get(timer)<=%lu iterations=%lu\n",
+                     millis, new_millis, mbedtls_timing_get_timer( &timer, 0 ),
+                     iterations );
+}
+/* END_CASE */
+
+/* BEGIN_CASE */
+void timing_timer_reset( )
+{
+    struct mbedtls_timing_hr_time timer;
+    unsigned long millis = 0;
+    unsigned long iterations = 0;
+
+    /* Skip this test if it looks like timers don't work at all, to avoid an
+       infinite loop below. */
+    TEST_ASSERT( !timers_are_badly_broken );
+
+    /* Start the timer. Timers are always reset to 0. */
+    TEST_ASSERT( mbedtls_timing_get_timer( &timer, 1 ) == 0 );
+    /* Busy-wait loop for a few milliseconds */
+    do
+    {
+        ++iterations;
+        millis = mbedtls_timing_get_timer( &timer, 0 );
+    }
+    while( millis < TIMING_SHORT_TEST_MS );
+
+    /* Reset the timer and check that it has restarted. */
+    TEST_ASSERT( mbedtls_timing_get_timer( &timer, 1 ) == 0 );
+    /* Read the timer immediately after reset. It should be 0 or close
+       to it. */
+    TEST_ASSERT( mbedtls_timing_get_timer( &timer, 0 ) < TIMING_SHORT_TEST_MS );
+    return;
+
+exit:
+    /* No cleanup needed, but show some diagnostic information, because timing
+       problems can be hard to reproduce. */
+    if( !timers_are_badly_broken )
+        mbedtls_fprintf( stdout, "  Finished with millis=%lu get(timer)<=%lu iterations=%lu\n",
+                         millis, mbedtls_timing_get_timer( &timer, 0 ),
+                         iterations );
+}
+/* END_CASE */
+
+/* BEGIN_CASE */
+void timing_two_timers( int delta )
+{
+    struct mbedtls_timing_hr_time timer1, timer2;
+    unsigned long millis1 = 0, millis2 = 0;
+
+    /* Skip this test if it looks like timers don't work at all, to avoid an
+       infinite loop below. */
+    TEST_ASSERT( !timers_are_badly_broken );
+
+    /* Start the first timer and wait for a short time. */
+    (void) mbedtls_timing_get_timer( &timer1, 1 );
+    do
+    {
+        millis1 = mbedtls_timing_get_timer( &timer1, 0 );
+    }
+    while( millis1 < TIMING_SHORT_TEST_MS );
+
+    /* Do a short busy-wait, so that the difference between timer1 and timer2
+       doesn't practically always end up being very close to a whole number of
+       milliseconds. */
+    while( delta > 0 )
+        --delta;
+
+    /* Start the second timer and compare it with the first. */
+    mbedtls_timing_get_timer( &timer2, 1 );
+    do
+    {
+        millis1 = mbedtls_timing_get_timer( &timer1, 0 );
+        millis2 = mbedtls_timing_get_timer( &timer2, 0 );
+        /* The first timer should always be ahead of the first. */
+        TEST_ASSERT( millis1 > millis2 );
+        /* The timers shouldn't drift apart, i.e. millis2-millis1 should stay
+           roughly constant, but this is hard to test reliably, especially in
+           a busy environment such as an overloaded continuous integration
+           system, so we don't test it it. */
+    }
+    while( millis2 < TIMING_SHORT_TEST_MS );
+
+    return;
+
+exit:
+    /* No cleanup needed, but show some diagnostic iterations, because timing
+       problems can be hard to reproduce. */
+    if( !timers_are_badly_broken )
+        mbedtls_fprintf( stdout, "  Finished with millis1=%lu get(timer1)<=%lu millis2=%lu get(timer2)<=%lu\n",
+                         millis1, mbedtls_timing_get_timer( &timer1, 0 ),
+                         millis2, mbedtls_timing_get_timer( &timer2, 0 ) );
+}
+/* END_CASE */
+
+/* BEGIN_CASE */
+void timing_alarm( int seconds )
+{
+    struct mbedtls_timing_hr_time timer;
+    unsigned long millis = 0;
+    /* We check that about the desired number of seconds has elapsed. Be
+       slightly liberal with the lower bound, so as to allow platforms where
+       the alarm (with second resolution) and the timer (with millisecond
+       resolution) are based on different clocks. Be very liberal with the
+       upper bound, because the platform might be busy. */
+    unsigned long millis_min = ( seconds > 0 ?
+                                 seconds * 900 :
+                                 0 );
+    unsigned long millis_max = ( seconds > 0 ?
+                                 seconds * 1100 + 400 :
+                                 TIMING_ALARM_0_DELAY_MS );
+    unsigned long iterations = 0;
+
+    /* Skip this test if it looks like timers don't work at all, to avoid an
+       infinite loop below. */
+    TEST_ASSERT( !timers_are_badly_broken );
+
+    /* Set an alarm and count how long it takes with a timer. */
+    (void) mbedtls_timing_get_timer( &timer, 1 );
+    mbedtls_set_alarm( seconds );
+
+    if( seconds > 0 )
+    {
+        /* We set the alarm for at least 1 second. It should not have fired
+           immediately, even on a slow and busy platform. */
+        TEST_ASSERT( !mbedtls_timing_alarmed );
+    }
+    /* A 0-second alarm should fire quickly, but we don't guarantee that it
+       fires immediately, so mbedtls_timing_alarmed may or may not be set at
+       this point. */
+
+    /* Busy-wait until the alarm rings */
+    do
+    {
+        ++iterations;
+        millis = mbedtls_timing_get_timer( &timer, 0 );
+    }
+    while( !mbedtls_timing_alarmed && millis <= millis_max );
+
+    TEST_ASSERT( mbedtls_timing_alarmed );
+    TEST_ASSERT( millis >= millis_min );
+    TEST_ASSERT( millis <= millis_max );
+
+    mbedtls_timing_alarmed = 0;
+    return;
+
+exit:
+    /* Show some diagnostic iterations, because timing
+       problems can be hard to reproduce. */
+    if( !timers_are_badly_broken )
+        mbedtls_fprintf( stdout, "  Finished with alarmed=%d millis=%lu get(timer)<=%lu iterations=%lu\n",
+                         mbedtls_timing_alarmed,
+                         millis, mbedtls_timing_get_timer( &timer, 0 ),
+                         iterations );
+    /* Cleanup */
+    mbedtls_timing_alarmed = 0;
+}
+/* END_CASE */
+
+/* BEGIN_CASE */
+void timing_delay( int int_ms, int fin_ms )
+{
+    /* This function assumes that if int_ms is nonzero then it is large
+       enough that we have time to read all timers at least once in an
+       interval of time lasting int_ms milliseconds, and likewise for (fin_ms
+       - int_ms). So don't call it with arguments that are too small. */
+
+    mbedtls_timing_delay_context delay;
+    struct mbedtls_timing_hr_time timer;
+    unsigned long delta = 0; /* delay started between timer=0 and timer=delta */
+    unsigned long before = 0, after = 0;
+    unsigned long iterations = 0;
+    int status = -2;
+    int saw_status_1 = 0;
+    int warn_inconclusive = 0;
+
+    assert( int_ms >= 0 );
+    assert( fin_ms >= 0 );
+
+    /* Skip this test if it looks like timers don't work at all, to avoid an
+       infinite loop below. */
+    TEST_ASSERT( !timers_are_badly_broken );
+
+    /* Start a reference timer. Program a delay, and verify that the status of
+       the delay is consistent with the time given by the reference timer. */
+    (void) mbedtls_timing_get_timer( &timer, 1 );
+    mbedtls_timing_set_delay( &delay, int_ms, fin_ms );
+    /* Set delta to an upper bound for the interval between the start of timer
+       and the start of delay. Reading timer after starting delay gives us an
+       upper bound for the interval, rounded to a 1ms precision. Since this
+       might have been rounded down, but we need an upper bound, we add 1. */
+    delta = mbedtls_timing_get_timer( &timer, 0 ) + 1;
+
+    status = mbedtls_timing_get_delay( &delay );
+    if( fin_ms == 0 )
+    {
+        /* Cancelled timer. Just check the correct status for this case. */
+        TEST_ASSERT( status == -1 );
+        return;
+    }
+
+    /* Initially, none of the delays must be passed yet if they're nonzero.
+       This could fail for very small values of int_ms and fin_ms, where "very
+       small" depends how fast and how busy the platform is. */
+    if( int_ms > 0 )
+    {
+        TEST_ASSERT( status == 0 );
+    }
+    else
+    {
+        TEST_ASSERT( status == 1 );
+    }
+
+    do
+    {
+        unsigned long delay_min, delay_max;
+        int status_min, status_max;
+        ++iterations;
+        before = mbedtls_timing_get_timer( &timer, 0 );
+        status = mbedtls_timing_get_delay( &delay );
+        after = mbedtls_timing_get_timer( &timer, 0 );
+        /* At a time between before and after, the delay's status was status.
+           Check that this is consistent given that the delay was started
+           between times 0 and delta. */
+        delay_min = ( before > delta ? before - delta : 0 );
+        status_min = expected_delay_status( int_ms, fin_ms, delay_min );
+        delay_max = after;
+        status_max = expected_delay_status( int_ms, fin_ms, delay_max );
+        TEST_ASSERT( status >= status_min );
+        TEST_ASSERT( status <= status_max );
+        if( status == 1 )
+            saw_status_1 = 1;
+    }
+    while ( before <= fin_ms + delta && status != 2 );
+
+    /* Since we've waited at least fin_ms, the delay must have fully
+       expired. */
+    TEST_ASSERT( status == 2 );
+
+    /* If the second delay is more than the first, then there must have been a
+       point in time when the first delay was passed but not the second delay.
+       This could fail for very small values of (fin_ms - int_ms), where "very
+       small" depends how fast and how busy the platform is. In practice, this
+       is the test that's most likely to fail on a heavily loaded machine. */
+    if( fin_ms > int_ms )
+    {
+        warn_inconclusive = 1;
+        TEST_ASSERT( saw_status_1 );
+    }
+
+    return;
+
+exit:
+    /* No cleanup needed, but show some diagnostic iterations, because timing
+       problems can be hard to reproduce. */
+    if( !timers_are_badly_broken )
+        mbedtls_fprintf( stdout, "  Finished with delta=%lu before=%lu after=%lu status=%d iterations=%lu\n",
+                         delta, before, after, status, iterations );
+    if( warn_inconclusive )
+        mbedtls_fprintf( stdout, "  Inconclusive test, try running it on a less heavily loaded machine.\n" );
+ }
+/* END_CASE */
+
+/* BEGIN_CASE */
+void timing_hardclock( )
+{
+    /* We make very few guarantees about mbedtls_timing_hardclock: its rate is
+       platform-dependent, it can wrap around. So there isn't much we can
+       test. But we do at least test that it doesn't crash, stall or return
+       completely nonsensical values. */
+
+    struct mbedtls_timing_hr_time timer;
+    unsigned long hardclock0 = -1, hardclock1 = -1, delta1 = -1;
+
+    /* Skip this test if it looks like timers don't work at all, to avoid an
+       infinite loop below. */
+    TEST_ASSERT( !timers_are_badly_broken );
+
+    hardclock0 = mbedtls_timing_hardclock( );
+    /* Wait 2ms to ensure a nonzero delay. Since the timer interface has 1ms
+       resolution and unspecified precision, waiting 1ms might be a very small
+       delay that's rounded up. */
+    (void) mbedtls_timing_get_timer( &timer, 1 );
+    while( mbedtls_timing_get_timer( &timer, 0 ) < 2 )
+        /*busy-wait loop*/;
+    hardclock1 = mbedtls_timing_hardclock( );
+
+    /* Although the hardclock counter can wrap around, the difference
+       (hardclock1 - hardclock0) is taken modulo the type size, so it is
+       correct as long as the counter only wrapped around at most once. We
+       further require the difference to be nonzero (after a wait of more than
+       1ms, the counter must have changed), and not to be overly large (after
+       a wait of less than 3ms, plus time lost because other processes were
+       scheduled on the CPU). If the hardclock counter runs at 4GHz, then
+       1000000000 (which is 1/4 of the counter wraparound on a 32-bit machine)
+       allows 250ms. */
+    delta1 = hardclock1 - hardclock0;
+    TEST_ASSERT( delta1 > 0 );
+    TEST_ASSERT( delta1 < 1000000000 );
+    return;
+
+exit:
+    /* No cleanup needed, but show some diagnostic iterations, because timing
+       problems can be hard to reproduce. */
+    if( !timers_are_badly_broken )
+        mbedtls_fprintf( stdout, "  Finished with hardclock=%lu,%lu\n",
+                         hardclock0, hardclock1 );
 }
 /* END_CASE */