Make sure memmove() is defined, even on SunOS 4.1.4.
[oweals/openssl.git] / crypto / x86cpuid.pl
index 85fbef7417b5e64b02bb989b697ed821a00e47d5..894c49c0a3e359d53bd38df178235d2a6290c829 100644 (file)
@@ -25,12 +25,12 @@ require "x86asm.pl";
        &mov    ("edx","ecx");
 &function_end("OPENSSL_ia32_cpuid");
 
-&external_label("OPENSSL_ia32cap");
+&external_label("OPENSSL_ia32cap_P");
 
-&function_begin_B("OPENSSL_rdtsc");
+&function_begin_B("OPENSSL_rdtsc","EXTRN\t_OPENSSL_ia32cap_P:DWORD");
        &xor    ("eax","eax");
        &xor    ("edx","edx");
-       &picmeup("ecx","OPENSSL_ia32cap");
+       &picmeup("ecx","OPENSSL_ia32cap_P");
        &bt     (&DWP(0,"ecx"),4);
        &jnc    (&label("notsc"));
        &rdtsc  ();
@@ -38,6 +38,40 @@ require "x86asm.pl";
        &ret    ();
 &function_end_B("OPENSSL_rdtsc");
 
-&initseg("OPENSSL_cpuid_setup") if ($main'elf);
+# This works in Ring 0 only [read DJGPP+MS-DOS+privileged DPMI host],
+# but it's safe to call it on any [supported] 32-bit platform...
+# Just check for [non-]zero return value...
+&function_begin_B("OPENSSL_instrument_halt","EXTRN\t_OPENSSL_ia32cap_P:DWORD");
+       &picmeup("ecx","OPENSSL_ia32cap_P");
+       &bt     (&DWP(0,"ecx"),4);
+       &jnc    (&label("nohalt"));     # no TSC
+
+       &data_word(0x9058900e);         # push %cs; pop %eax
+       &and    ("eax",3);
+       &jnz    (&label("nohalt"));     # not enough privileges
+
+       &pushf  ();
+       &pop    ("eax")
+       &bt     ("eax",9);
+       &jnc    (&label("nohalt"));     # interrupts are disabled
+
+       &rdtsc  ();
+       &push   ("edx");
+       &push   ("eax");
+       &halt   ();
+       &rdtsc  ();
+
+       &sub    ("eax",&DWP(0,"esp"));
+       &sbb    ("edx",&DWP(4,"esp"));
+       &add    ("esp",8);
+       &ret    ();
+
+&set_label("nohalt");
+       &xor    ("eax","eax");
+       &xor    ("edx","edx");
+       &ret    ();
+&function_end_B("OPENSSL_instrument_halt");
+
+&initseg("OPENSSL_cpuid_setup");
 
 &asm_finish();