+/* fixs390: anything for s390x here ? */
+
+/* For hwcaps detection on ppc32/64, s390x, and arm we'll need to do SIGILL
+ testing, so we need a VG_MINIMAL_JMP_BUF. */
+#if defined(VGA_ppc32) || defined(VGA_ppc64) \
+ || defined(VGA_arm) || defined(VGA_s390x)
+#include "pub_tool_libcsetjmp.h"
+static VG_MINIMAL_JMP_BUF(env_unsup_insn);
+static void handler_unsup_insn ( Int x ) {
+ VG_MINIMAL_LONGJMP(env_unsup_insn);
+}
+#endif
+
+
+/* Helper function for VG_(machine_get_hwcaps), assumes the SIGILL/etc
+ * handlers are installed. Determines the the sizes affected by dcbz
+ * and dcbzl instructions and updates the given VexArchInfo structure
+ * accordingly.
+ *
+ * Not very defensive: assumes that as long as the dcbz/dcbzl
+ * instructions don't raise a SIGILL, that they will zero an aligned,
+ * contiguous block of memory of a sensible size. */
+#if defined(VGA_ppc32) || defined(VGA_ppc64)
+static void find_ppc_dcbz_sz(VexArchInfo *arch_info)
+{
+ Int dcbz_szB = 0;
+ Int dcbzl_szB;
+# define MAX_DCBZL_SZB (128) /* largest known effect of dcbzl */
+ char test_block[4*MAX_DCBZL_SZB];
+ char *aligned = test_block;
+ Int i;
+
+ /* round up to next max block size, assumes MAX_DCBZL_SZB is pof2 */
+ aligned = (char *)(((HWord)aligned + MAX_DCBZL_SZB) & ~(MAX_DCBZL_SZB - 1));
+ vg_assert((aligned + MAX_DCBZL_SZB) <= &test_block[sizeof(test_block)]);
+
+ /* dcbz often clears 32B, although sometimes whatever the native cache
+ * block size is */
+ VG_(memset)(test_block, 0xff, sizeof(test_block));
+ __asm__ __volatile__("dcbz 0,%0"
+ : /*out*/
+ : "r" (aligned) /*in*/
+ : "memory" /*clobber*/);
+ for (dcbz_szB = 0, i = 0; i < sizeof(test_block); ++i) {
+ if (!test_block[i])
+ ++dcbz_szB;
+ }
+ vg_assert(dcbz_szB == 32 || dcbz_szB == 64 || dcbz_szB == 128);
+
+ /* dcbzl clears 128B on G5/PPC970, and usually 32B on other platforms */
+ if (VG_MINIMAL_SETJMP(env_unsup_insn)) {
+ dcbzl_szB = 0; /* indicates unsupported */
+ }
+ else {
+ VG_(memset)(test_block, 0xff, sizeof(test_block));
+ /* some older assemblers won't understand the dcbzl instruction
+ * variant, so we directly emit the instruction ourselves */
+ __asm__ __volatile__("mr 9, %0 ; .long 0x7C204FEC" /*dcbzl 0,9*/
+ : /*out*/
+ : "r" (aligned) /*in*/
+ : "memory", "r9" /*clobber*/);
+ for (dcbzl_szB = 0, i = 0; i < sizeof(test_block); ++i) {
+ if (!test_block[i])
+ ++dcbzl_szB;
+ }
+ vg_assert(dcbzl_szB == 32 || dcbzl_szB == 64 || dcbzl_szB == 128);
+ }
+
+ arch_info->ppc_dcbz_szB = dcbz_szB;
+ arch_info->ppc_dcbzl_szB = dcbzl_szB;
+
+ VG_(debugLog)(1, "machine", "dcbz_szB=%d dcbzl_szB=%d\n",
+ dcbz_szB, dcbzl_szB);
+# undef MAX_DCBZL_SZB
+}
+#endif /* defined(VGA_ppc32) || defined(VGA_ppc64) */
+
+#ifdef VGA_s390x
+
+/* Read /proc/cpuinfo. Look for lines like these
+
+ processor 0: version = FF, identification = 0117C9, machine = 2064
+
+ and return the machine model or VEX_S390X_MODEL_INVALID on error. */
+
+static UInt VG_(get_machine_model)(void)
+{
+ static struct model_map {
+ HChar name[5];
+ UInt id;
+ } model_map[] = {
+ { "2064", VEX_S390X_MODEL_Z900 },
+ { "2066", VEX_S390X_MODEL_Z800 },
+ { "2084", VEX_S390X_MODEL_Z990 },
+ { "2086", VEX_S390X_MODEL_Z890 },
+ { "2094", VEX_S390X_MODEL_Z9_EC },
+ { "2096", VEX_S390X_MODEL_Z9_BC },
+ { "2097", VEX_S390X_MODEL_Z10_EC },
+ { "2098", VEX_S390X_MODEL_Z10_BC },
+ { "2817", VEX_S390X_MODEL_Z196 },
+ };
+
+ Int model, n, fh;
+ SysRes fd;
+ SizeT num_bytes, file_buf_size;
+ HChar *p, *m, *model_name, *file_buf;
+
+ /* Slurp contents of /proc/cpuinfo into FILE_BUF */
+ fd = VG_(open)( "/proc/cpuinfo", 0, VKI_S_IRUSR );
+ if ( sr_isError(fd) ) return VEX_S390X_MODEL_INVALID;
+
+ fh = sr_Res(fd);
+
+ /* Determine the size of /proc/cpuinfo.
+ Work around broken-ness in /proc file system implementation.
+ fstat returns a zero size for /proc/cpuinfo although it is
+ claimed to be a regular file. */
+ num_bytes = 0;
+ file_buf_size = 1000;
+ file_buf = VG_(malloc)("cpuinfo", file_buf_size + 1);
+ while (42) {
+ n = VG_(read)(fh, file_buf, file_buf_size);
+ if (n < 0) break;
+
+ num_bytes += n;
+ if (n < file_buf_size) break; /* reached EOF */
+ }
+
+ if (n < 0) num_bytes = 0; /* read error; ignore contents */
+
+ if (num_bytes > file_buf_size) {
+ VG_(free)( file_buf );
+ VG_(lseek)( fh, 0, VKI_SEEK_SET );
+ file_buf = VG_(malloc)( "cpuinfo", num_bytes + 1 );
+ n = VG_(read)( fh, file_buf, num_bytes );
+ if (n < 0) num_bytes = 0;
+ }
+
+ file_buf[num_bytes] = '\0';
+ VG_(close)(fh);
+
+ /* Parse file */
+ model = VEX_S390X_MODEL_INVALID;
+ for (p = file_buf; *p; ++p) {
+ /* Beginning of line */
+ if (VG_(strncmp)( p, "processor", sizeof "processor" - 1 ) != 0) continue;
+
+ m = VG_(strstr)( p, "machine" );
+ if (m == NULL) continue;
+
+ p = m + sizeof "machine" - 1;
+ while ( VG_(isspace)( *p ) || *p == '=') {
+ if (*p == '\n') goto next_line;
+ ++p;
+ }
+
+ model_name = p;
+ for (n = 0; n < sizeof model_map / sizeof model_map[0]; ++n) {
+ struct model_map *mm = model_map + n;
+ SizeT len = VG_(strlen)( mm->name );
+ if ( VG_(strncmp)( mm->name, model_name, len ) == 0 &&
+ VG_(isspace)( model_name[len] )) {
+ if (mm->id < model) model = mm->id;
+ p = model_name + len;
+ break;
+ }
+ }
+ /* Skip until end-of-line */
+ while (*p != '\n')
+ ++p;
+ next_line: ;
+ }
+
+ VG_(free)( file_buf );
+ VG_(debugLog)(1, "machine", "model = %s\n", model_map[model].name);
+
+ return model;
+}
+
+#endif /* VGA_s390x */