1#!/usr/bin/env perl 2 3push(@INC,"perlasm"); 4require "x86asm.pl"; 5 6&asm_init($ARGV[0],"x86cpuid"); 7 8for (@ARGV) { $sse2=1 if (/-DOPENSSL_IA32_SSE2/); } 9 10&function_begin("OPENSSL_ia32_cpuid"); 11 &xor ("edx","edx"); 12 &pushf (); 13 &pop ("eax"); 14 &mov ("ecx","eax"); 15 &xor ("eax",1<<21); 16 &push ("eax"); 17 &popf (); 18 &pushf (); 19 &pop ("eax"); 20 &xor ("ecx","eax"); 21 &bt ("ecx",21); 22 &jnc (&label("nocpuid")); 23 &mov ("eax",1); 24 &cpuid (); 25&set_label("nocpuid"); 26 &mov ("eax","edx"); 27 &mov ("edx","ecx"); 28&function_end("OPENSSL_ia32_cpuid"); 29 30&external_label("OPENSSL_ia32cap_P"); 31 32&function_begin_B("OPENSSL_rdtsc","EXTRN\t_OPENSSL_ia32cap_P:DWORD"); 33 &xor ("eax","eax"); 34 &xor ("edx","edx"); 35 &picmeup("ecx","OPENSSL_ia32cap_P"); 36 &bt (&DWP(0,"ecx"),4); 37 &jnc (&label("notsc")); 38 &rdtsc (); 39&set_label("notsc"); 40 &ret (); 41&function_end_B("OPENSSL_rdtsc"); 42 43# This works in Ring 0 only [read DJGPP+MS-DOS+privileged DPMI host], 44# but it's safe to call it on any [supported] 32-bit platform... 45# Just check for [non-]zero return value... 46&function_begin_B("OPENSSL_instrument_halt","EXTRN\t_OPENSSL_ia32cap_P:DWORD"); 47 &picmeup("ecx","OPENSSL_ia32cap_P"); 48 &bt (&DWP(0,"ecx"),4); 49 &jnc (&label("nohalt")); # no TSC 50 51 &data_word(0x9058900e); # push %cs; pop %eax 52 &and ("eax",3); 53 &jnz (&label("nohalt")); # not enough privileges 54 55 &pushf (); 56 &pop ("eax") 57 &bt ("eax",9); 58 &jnc (&label("nohalt")); # interrupts are disabled 59 60 &rdtsc (); 61 &push ("edx"); 62 &push ("eax"); 63 &halt (); 64 &rdtsc (); 65 66 &sub ("eax",&DWP(0,"esp")); 67 &sbb ("edx",&DWP(4,"esp")); 68 &add ("esp",8); 69 &ret (); 70 71&set_label("nohalt"); 72 &xor ("eax","eax"); 73 &xor ("edx","edx"); 74 &ret (); 75&function_end_B("OPENSSL_instrument_halt"); 76 77# Essentially there is only one use for this function. Under DJGPP: 78# 79# #include <go32.h> 80# ... 81# i=OPENSSL_far_spin(_dos_ds,0x46c); 82# ... 83# to obtain the number of spins till closest timer interrupt. 84 85&function_begin_B("OPENSSL_far_spin"); 86 &pushf (); 87 &pop ("eax") 88 &bt ("eax",9); 89 &jnc (&label("nospin")); # interrupts are disabled 90 91 &mov ("eax",&DWP(4,"esp")); 92 &mov ("ecx",&DWP(8,"esp")); 93 &data_word (0x90d88e1e); # push %ds, mov %eax,%ds 94 &xor ("eax","eax"); 95 &mov ("edx",&DWP(0,"ecx")); 96 &jmp (&label("spin")); 97 98 &align (16); 99&set_label("spin"); 100 &inc ("eax"); 101 &cmp ("edx",&DWP(0,"ecx")); 102 &je (&label("spin")); 103 104 &data_word (0x1f909090); # pop %ds 105 &ret (); 106 107&set_label("nospin"); 108 &xor ("eax","eax"); 109 &xor ("edx","edx"); 110 &ret (); 111&function_end_B("OPENSSL_far_spin"); 112 113&function_begin_B("OPENSSL_wipe_cpu","EXTRN\t_OPENSSL_ia32cap_P:DWORD"); 114 &xor ("eax","eax"); 115 &xor ("edx","edx"); 116 &picmeup("ecx","OPENSSL_ia32cap_P"); 117 &mov ("ecx",&DWP(0,"ecx")); 118 &bt (&DWP(0,"ecx"),1); 119 &jnc (&label("no_x87")); 120 if ($sse2) { 121 &bt (&DWP(0,"ecx"),26); 122 &jnc (&label("no_sse2")); 123 &pxor ("xmm0","xmm0"); 124 &pxor ("xmm1","xmm1"); 125 &pxor ("xmm2","xmm2"); 126 &pxor ("xmm3","xmm3"); 127 &pxor ("xmm4","xmm4"); 128 &pxor ("xmm5","xmm5"); 129 &pxor ("xmm6","xmm6"); 130 &pxor ("xmm7","xmm7"); 131 &set_label("no_sse2"); 132 } 133 # just a bunch of fldz to zap the fp/mm bank followed by finit... 134 &data_word(0xeed9eed9,0xeed9eed9,0xeed9eed9,0xeed9eed9,0x90e3db9b); 135&set_label("no_x87"); 136 &lea ("eax",&DWP(4,"esp")); 137 &ret (); 138&function_end_B("OPENSSL_wipe_cpu"); 139 140&function_begin_B("OPENSSL_atomic_add"); 141 &mov ("edx",&DWP(4,"esp")); # fetch the pointer, 1st arg 142 &mov ("ecx",&DWP(8,"esp")); # fetch the increment, 2nd arg 143 &push ("ebx"); 144 &nop (); 145 &mov ("eax",&DWP(0,"edx")); 146&set_label("spin"); 147 &lea ("ebx",&DWP(0,"eax","ecx")); 148 &nop (); 149 &data_word(0x1ab10ff0); # lock; cmpxchg %ebx,(%edx) # %eax is envolved and is always reloaded 150 &jne (&label("spin")); 151 &mov ("eax","ebx"); # OpenSSL expects the new value 152 &pop ("ebx"); 153 &ret (); 154&function_end_B("OPENSSL_atomic_add"); 155 156# This function can become handy under Win32 in situations when 157# we don't know which calling convention, __stdcall or __cdecl(*), 158# indirect callee is using. In C it can be deployed as 159# 160#ifdef OPENSSL_CPUID_OBJ 161# type OPENSSL_indirect_call(void *f,...); 162# ... 163# OPENSSL_indirect_call(func,[up to $max arguments]); 164#endif 165# 166# (*) it's designed to work even for __fastcall if number of 167# arguments is 1 or 2! 168&function_begin_B("OPENSSL_indirect_call"); 169 { 170 my $i,$max=7; # $max has to be chosen as 4*n-1 171 # in order to preserve eventual 172 # stack alignment 173 &push ("ebp"); 174 &mov ("ebp","esp"); 175 &sub ("esp",$max*4); 176 &mov ("ecx",&DWP(12,"ebp")); 177 &mov (&DWP(0,"esp"),"ecx"); 178 &mov ("edx",&DWP(16,"ebp")); 179 &mov (&DWP(4,"esp"),"edx"); 180 for($i=2;$i<$max;$i++) 181 { 182 # Some copies will be redundant/bogus... 183 &mov ("eax",&DWP(12+$i*4,"ebp")); 184 &mov (&DWP(0+$i*4,"esp"),"eax"); 185 } 186 &call_ptr (&DWP(8,"ebp"));# make the call... 187 &mov ("esp","ebp"); # ... and just restore the stack pointer 188 # without paying attention to what we called, 189 # (__cdecl *func) or (__stdcall *one). 190 &pop ("ebp"); 191 &ret (); 192 } 193&function_end_B("OPENSSL_indirect_call"); 194 195&initseg("OPENSSL_cpuid_setup"); 196 197&asm_finish(); 198