Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions VEX/priv/guest_arm64_defs.h
Original file line number Diff line number Diff line change
Expand Up @@ -132,6 +132,8 @@ extern ULong arm64g_dirtyhelper_MRS_ID_AA64MMFR1_EL1 ( void );
extern ULong arm64g_dirtyhelper_MRS_ID_AA64ISAR0_EL1 ( void );
extern ULong arm64g_dirtyhelper_MRS_ID_AA64ISAR1_EL1 ( void );

extern void arm64g_dirtyhelper_RNDR ( /*OUT*/V128* res, ULong reseed );

extern void arm64g_dirtyhelper_PMULLQ ( /*OUT*/V128* res,
ULong arg1, ULong arg2 );

Expand Down
40 changes: 37 additions & 3 deletions VEX/priv/guest_arm64_helpers.c
Original file line number Diff line number Diff line change
Expand Up @@ -924,10 +924,11 @@ ULong arm64g_dirtyhelper_MRS_ID_AA64ISAR0_EL1 ( void )
// 9 - SM3 (unsupported)
// 10 - SM4 (unsupported)
// 11 - DP
// 15 - RNDR

// 10
// 109876543210
w &= 0xF000F0FFFFFF;
// 1 10
// 5432109876543210
w &= 0xF000F000F0FFFFFFULL;

return w;
# else
Expand All @@ -953,6 +954,39 @@ ULong arm64g_dirtyhelper_MRS_ID_AA64ISAR1_EL1 ( void )
# endif
}

/* CALLED FROM GENERATED CODE */
/* DIRTY HELPER (non-referentially-transparent) */
/* Read RNDR (reseed == 0) or RNDRRS (reseed != 0). Writes the random value
to res->w64[0] and the resulting NZCV, in bits 31:28, to res->w64[1]. With
a deterministic RNG installed, both read the calling thread's stream and
always succeed. Otherwise the host's register is read. On non-arm64
hosts, report failure. */
void arm64g_dirtyhelper_RNDR ( /*OUT*/V128* res, ULong reseed )
{
if (vex_random32) {
ULong lo = vex_random32();
ULong hi = vex_random32();
res->w64[0] = (hi << 32) | lo;
res->w64[1] = 0;
return;
}
# if defined(__aarch64__) && !defined(__arm__)
ULong value = 0;
ULong nzcv = 0;
if (reseed)
__asm__ __volatile__("mrs %0, s3_3_c2_c4_1 ; mrs %1, nzcv"
: "=r"(value), "=r"(nzcv) : : "cc");
else
__asm__ __volatile__("mrs %0, s3_3_c2_c4_0 ; mrs %1, nzcv"
: "=r"(value), "=r"(nzcv) : : "cc");
res->w64[0] = value;
res->w64[1] = nzcv & (0xFULL << ARM64G_CC_SHIFT_V);
# else
res->w64[0] = 0;
res->w64[1] = 1ULL << ARM64G_CC_SHIFT_Z;
# endif
}

void arm64g_dirtyhelper_PMULLQ ( /*OUT*/V128* res, ULong arg1, ULong arg2 )
{
/* This doesn't need to be a dirty helper, except for the fact that
Expand Down
28 changes: 28 additions & 0 deletions VEX/priv/guest_arm64_toIR.c
Original file line number Diff line number Diff line change
Expand Up @@ -7978,6 +7978,34 @@ Bool dis_ARM64_branch_etc(/*MB_OUT*/DisResult* dres, UInt insn,
DIP("mrs %s, cntfrq_el0\n", nameIReg64orZR(tt));
return True;
}
/* ---- Cases for RNDR and RNDRRS (FEAT_RNG) ----
D5 3B 24 000 Rt MRS Xt, rndr
D5 3B 24 001 Rt MRS Xt, rndrrs
Decoded when the host has FEAT_RNG, or when a deterministic RNG is
installed, since then the host register is never read. On success
NZCV is 0000; on failure Xt is 0 and NZCV is 0100.
*/
if ((INSN(31,0) & 0xFFFFFFC0) == 0xD53B2400
&& ((archinfo->hwcaps & VEX_HWCAPS_ARM64_RNG) || vex_random32)) {
UInt tt = INSN(4,0);
Bool reseed = INSN(5,5) == 1;
IRTemp pair = newTemp(Ity_V128);
IRDirty* d = unsafeIRDirty_1_N(
pair,
0/*regparms*/,
"arm64g_dirtyhelper_RNDR",
&arm64g_dirtyhelper_RNDR,
mkIRExprVec_2(IRExpr_VECRET(),
mkU64(reseed ? 1 : 0))
);
stmt( IRStmt_Dirty(d) );
IRTemp nzcv = newTemp(Ity_I64);
assign(nzcv, unop(Iop_V128HIto64, mkexpr(pair)));
putIReg64orZR(tt, unop(Iop_V128to64, mkexpr(pair)));
setFlags_COPY(nzcv);
DIP("mrs %s, %s\n", nameIReg64orZR(tt), reseed ? "rndrrs" : "rndr");
return True;
}

/* ------------------ IC_IVAU ------------------ */
/* D5 0B 75 001 Rt ic ivau, rT
Expand Down
1 change: 1 addition & 0 deletions VEX/priv/main_main.c
Original file line number Diff line number Diff line change
Expand Up @@ -1913,6 +1913,7 @@ static const HChar* show_hwcaps_arm64 ( UInt hwcaps )
{ VEX_HWCAPS_ARM64_BF16, "bf16" },
{ VEX_HWCAPS_ARM64_FP16, "fp16" },
{ VEX_HWCAPS_ARM64_VFP16, "vfp16" },
{ VEX_HWCAPS_ARM64_RNG, "rng" },
};

static HChar buf[sizeof prefix + // '\0'
Expand Down
1 change: 1 addition & 0 deletions VEX/pub/libvex.h
Original file line number Diff line number Diff line change
Expand Up @@ -242,6 +242,7 @@ typedef
#define VEX_HWCAPS_ARM64_BF16 (1 << 13)
#define VEX_HWCAPS_ARM64_FP16 (1 << 14)
#define VEX_HWCAPS_ARM64_VFP16 (1 << 15)
#define VEX_HWCAPS_ARM64_RNG (1 << 16)

/* MIPS baseline capability */
/* Assigned Company values for bits 23:16 of the PRId Register
Expand Down
8 changes: 8 additions & 0 deletions coregrind/m_initimg/initimg-linux.c
Original file line number Diff line number Diff line change
Expand Up @@ -894,6 +894,14 @@ Addr setup_client_stack( void* init_sp,
break;
# endif

# if defined(VGP_arm64_linux)
case AT_HWCAP2:
/* Limit AT_HWCAP2 to the features VEX supports. RNDR and RNDRRS
are decoded whenever the host has FEAT_RNG. */
auxv->u.a_val &= VKI_HWCAP2_RNG;
break;
# endif

case AT_ICACHEBSIZE:
case AT_DCACHEBSIZE:
case AT_UCACHEBSIZE:
Expand Down
13 changes: 11 additions & 2 deletions coregrind/m_machine.c
Original file line number Diff line number Diff line change
Expand Up @@ -1856,11 +1856,11 @@ Bool VG_(machine_get_hwcaps)( void )

Bool have_fhm, have_dp, have_sm4, have_sm3, have_sha3, have_rdm;
Bool have_atomics, have_i8mm, have_bf16, have_dpbcvap, have_dpbcvadp;
Bool have_vfp16, have_fp16;
Bool have_vfp16, have_fp16, have_rng;

have_fhm = have_dp = have_sm4 = have_sm3 = have_sha3 = have_rdm
= have_atomics = have_i8mm = have_bf16 = have_dpbcvap
= have_dpbcvadp = have_vfp16 = have_fp16 = False;
= have_dpbcvadp = have_vfp16 = have_fp16 = have_rng = False;

/* Some baseline v8.0 kernels do not allow reads of these registers. Use
* the same SIGILL handling algorithm as other architectures for such
Expand Down Expand Up @@ -1938,6 +1938,7 @@ Bool VG_(machine_get_hwcaps)( void )
return True;

/* ID_AA64ISAR0_EL1 Instruction set attribute register 0 fields */
#define ID_AA64ISAR0_RNDR_SHIFT 60
#define ID_AA64ISAR0_FHM_SHIFT 48
#define ID_AA64ISAR0_DP_SHIFT 44
#define ID_AA64ISAR0_SM4_SHIFT 40
Expand All @@ -1946,6 +1947,7 @@ Bool VG_(machine_get_hwcaps)( void )
#define ID_AA64ISAR0_RDM_SHIFT 28
#define ID_AA64ISAR0_ATOMICS_SHIFT 20
/* Field values */
#define ID_AA64ISAR0_RNDR_SUPPORTED 0x1
#define ID_AA64ISAR0_FHM_SUPPORTED 0x1
#define ID_AA64ISAR0_DP_SUPPORTED 0x1
#define ID_AA64ISAR0_SM4_SUPPORTED 0x1
Expand Down Expand Up @@ -2032,6 +2034,12 @@ Bool VG_(machine_get_hwcaps)( void )
get_ftr(ID_AA64ISAR0_EL1, ID_AA64ISAR0_ATOMICS_SHIFT,
ID_AA64ISAR0_ATOMICS_SUPPORTED, have_atomics);

/* RNDR indicates support for the RNDR and RNDRRS registers.
* Optional for v8.5.
*/
get_ftr(ID_AA64ISAR0_EL1, ID_AA64ISAR0_RNDR_SHIFT,
ID_AA64ISAR0_RNDR_SUPPORTED, have_rng);

/* Read ID_AA64ISAR1_EL1 attributes */

/* I8MM indicates support for SMMLA, SUDOT, UMMLA, USMMLA, and USDOT
Expand Down Expand Up @@ -2086,6 +2094,7 @@ Bool VG_(machine_get_hwcaps)( void )
if (have_bf16) vai.hwcaps |= VEX_HWCAPS_ARM64_BF16;
if (have_fp16) vai.hwcaps |= VEX_HWCAPS_ARM64_FP16;
if (have_vfp16) vai.hwcaps |= VEX_HWCAPS_ARM64_VFP16;
if (have_rng) vai.hwcaps |= VEX_HWCAPS_ARM64_RNG;

#undef get_cpu_ftr
#undef get_ftr
Expand Down
2 changes: 1 addition & 1 deletion coregrind/m_main.c
Original file line number Diff line number Diff line change
Expand Up @@ -108,7 +108,7 @@ static void usage_NORETURN ( int need_help )
" to run despite their file capabilities, which\n"
" they do not get under Valgrind\n"
" --deterministic-rng=no|yes serve AT_RANDOM, getrandom() and /dev/urandom\n"
" and RDRAND/RDSEED from a fixed-seed PRNG [no]\n"
" and hardware RNG insns from a fixed-seed PRNG [no]\n"
" --child-silent-after-fork=no|yes omit child output between fork & exec? [no]\n"
" --vgdb=no|yes|full activate gdbserver? [yes]\n"
" full is slower but provides precise watchpoint/step\n"
Expand Down
8 changes: 7 additions & 1 deletion docs/xml/manual-core.xml
Original file line number Diff line number Diff line change
Expand Up @@ -814,7 +814,13 @@ in most cases. We group the available options by rough categories.</para>
<computeroutput>RDRAND</computeroutput> and
<computeroutput>RDSEED</computeroutput>. On hosts that support them,
programs that execute them anyway draw from the calling thread's PRNG
stream, which always reports success.</para>
stream, which always reports success. On arm64,
<computeroutput>RNDR</computeroutput> and
<computeroutput>RNDRRS</computeroutput> draw from the same stream and
always report success, also on hosts without FEAT_RNG.
<computeroutput>HWCAP2_RNG</computeroutput> and
<computeroutput>ID_AA64ISAR0_EL1.RNDR</computeroutput> still report
them only when the host supports them.</para>
<para>For nonempty random-device
<computeroutput>preadv2</computeroutput> reads, the supported flags are
<computeroutput>RWF_HIPRI</computeroutput>,
Expand Down
2 changes: 2 additions & 0 deletions include/vki/vki-arm64-linux.h
Original file line number Diff line number Diff line change
Expand Up @@ -730,6 +730,8 @@ struct vki_shminfo64 {
#define VKI_HWCAP_ILRCPC (1 << 26)
#define VKI_HWCAP_FLAGM (1 << 27)

#define VKI_HWCAP2_RNG (1 << 16)

//----------------------------------------------------------------------
// And that's it!
//----------------------------------------------------------------------
Expand Down
4 changes: 4 additions & 0 deletions none/tests/arm64/Makefile.am
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@ EXTRA_DIST = \
crc32.stdout.exp crc32.stderr.exp crc32.vgtest \
cvtf_imm.stdout.exp cvtf_imm.stderr.exp cvtf_imm.vgtest \
dc_cvax.vgtest dc_cvax.stderr.exp \
deterministic_rng.stdout.exp deterministic_rng.stderr.exp \
deterministic_rng.vgtest \
fcvta_s_u.vgtest fcvta_s_u.stderr.exp \
fp_and_simd.stdout.exp fp_and_simd.stderr.exp fp_and_simd.vgtest \
frinta_frintn.stderr.exp frinta_frintn.vgtest \
Expand All @@ -33,6 +35,7 @@ check_PROGRAMS = \
bug489338 \
cvtf_imm \
dc_cvax \
deterministic_rng \
fp_and_simd \
integer \
memory_test \
Expand Down Expand Up @@ -92,6 +95,7 @@ fp_and_simd_v82_SOURCES = fp_and_simd_v82.c simd.h simd.c
sha512_v82_SOURCES = sha512_v82.c simd.h simd.c

bug489338_LDADD = -lm
deterministic_rng_LDADD = -lpthread
fp_and_simd_LDADD = -lm
simd_v81_LDADD = -lm
fp_and_simd_v82_LDADD = -lm
Expand Down
46 changes: 46 additions & 0 deletions none/tests/arm64/deterministic_rng.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
#include <assert.h>
#include <pthread.h>
#include <stdint.h>
#include <stdio.h>

enum {
NZCV_ALL = 0xf0000000,
NZCV_SUCCESS = 0,
DRAW_COUNT = 2
};

#define REGISTER_SENTINEL UINT64_C(0x5555555555555555)

/* Use the generic register names so the test assembles without +rng. */
#define DRAW(name, sysreg) \
static void* name(void* unused) \
{ \
(void)unused; \
for (int i = 0; i < DRAW_COUNT; i++) { \
uint64_t value = REGISTER_SENTINEL; \
uint64_t nzcv; \
__asm__ volatile("msr nzcv, %2; mrs %0, " sysreg "; mrs %1, nzcv" \
: "=&r"(value), "=&r"(nzcv) \
: "r"((uint64_t)NZCV_ALL) : "cc"); \
assert((nzcv & NZCV_ALL) == NZCV_SUCCESS); \
printf(#name ": %016llx\n", (unsigned long long)value); \
} \
return NULL; \
}

DRAW(rndr, "s3_3_c2_c4_0")
DRAW(rndrrs, "s3_3_c2_c4_1")

int main(void)
{
void* (*draws[])(void*) = { rndr, rndrrs };
/* Fresh threads keep expected bytes independent of libc startup draws. */
for (unsigned int i = 0; i < sizeof(draws) / sizeof(draws[0]); i++) {
pthread_t thread;
int err = pthread_create(&thread, NULL, draws[i], NULL);
assert(err == 0);
err = pthread_join(thread, NULL);
assert(err == 0);
}
return 0;
}
Empty file.
4 changes: 4 additions & 0 deletions none/tests/arm64/deterministic_rng.stdout.exp
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
rndr: 5ef4b5199914d78e
rndr: 7fb4c3bf72a5486f
rndrrs: b8e63bec131a7a6b
rndrrs: f1aa70fe9100862e
3 changes: 3 additions & 0 deletions none/tests/arm64/deterministic_rng.vgtest
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
prog: deterministic_rng
prereq: test -x deterministic_rng
vgopts: -q --deterministic-rng=yes
2 changes: 1 addition & 1 deletion none/tests/cmdline1.stdout.exp
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ usage: valgrind [options] prog-and-args
to run despite their file capabilities, which
they do not get under Valgrind
--deterministic-rng=no|yes serve AT_RANDOM, getrandom() and /dev/urandom
and RDRAND/RDSEED from a fixed-seed PRNG [no]
and hardware RNG insns from a fixed-seed PRNG [no]
--child-silent-after-fork=no|yes omit child output between fork & exec? [no]
--vgdb=no|yes|full activate gdbserver? [yes]
full is slower but provides precise watchpoint/step
Expand Down
2 changes: 1 addition & 1 deletion none/tests/cmdline2.stdout.exp
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ usage: valgrind [options] prog-and-args
to run despite their file capabilities, which
they do not get under Valgrind
--deterministic-rng=no|yes serve AT_RANDOM, getrandom() and /dev/urandom
and RDRAND/RDSEED from a fixed-seed PRNG [no]
and hardware RNG insns from a fixed-seed PRNG [no]
--child-silent-after-fork=no|yes omit child output between fork & exec? [no]
--vgdb=no|yes|full activate gdbserver? [yes]
full is slower but provides precise watchpoint/step
Expand Down
Loading