Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

397 lines
8.1 KiB

  1. #include "setupp.h"
  2. #pragma hdrstop
  3. //
  4. // TRUE if we detected a flawed pentium chip.
  5. //
  6. BOOL FlawedPentium;
  7. //
  8. // TRUE if NPX emulation is forced on.
  9. // Flag indicating what user wants to do.
  10. //
  11. BOOL CurrentNpxSetting;
  12. BOOL UserNpxSetting;
  13. //
  14. // Name of value in HKLM\System\CurrentControlSet\Control\Session Manager
  15. // controlling npx emulation.
  16. //
  17. PCWSTR NpxEmulationKey = L"System\\CurrentControlSet\\Control\\Session Manager";
  18. PCWSTR NpxEmulationValue = L"ForceNpxEmulation";
  19. BOOL
  20. TestForDivideError(
  21. VOID
  22. );
  23. int
  24. ms_p5_test_fdiv(
  25. void
  26. );
  27. VOID
  28. CheckPentium(
  29. VOID
  30. )
  31. /*++
  32. Routine Description:
  33. Check all processor(s) for the Pentium floating-point devide errata.
  34. Arguments:
  35. None.
  36. Return Value:
  37. None. Global variables FlawedPentium, CurrentNpxSetting, and
  38. UserNpxSetting will be filled in.
  39. --*/
  40. {
  41. LONG rc;
  42. HKEY hKey;
  43. DWORD DataType;
  44. DWORD ForcedOn;
  45. DWORD DataSize;
  46. static LONG CheckedPentium = -1;
  47. //
  48. // If we didn't already check it CheckedPentium will become 0
  49. // with this increment. If we already checked it then CheckedPentium
  50. // will become something greater than 0.
  51. //
  52. if(InterlockedIncrement(&CheckedPentium)) {
  53. return;
  54. }
  55. //
  56. // Perform division test to see whether pentium is flawed.
  57. //
  58. if(FlawedPentium = TestForDivideError()) {
  59. SetuplogError(
  60. LogSevInformation,
  61. SETUPLOG_USE_MESSAGEID,
  62. MSG_LOG_FLAWED_PENTIUM,
  63. 0,0);
  64. }
  65. //
  66. // Check registry to see whether npx is currently forced on. Assume not.
  67. //
  68. CurrentNpxSetting = 0;
  69. rc = RegOpenKeyEx(HKEY_LOCAL_MACHINE,NpxEmulationKey,0,KEY_QUERY_VALUE,&hKey);
  70. if(rc == NO_ERROR) {
  71. DataSize = sizeof(DWORD);
  72. rc = RegQueryValueEx(
  73. hKey,
  74. NpxEmulationValue,
  75. 0,
  76. &DataType,
  77. (PBYTE)&ForcedOn,
  78. &DataSize
  79. );
  80. //
  81. // If the value isn't present then assume emulation
  82. // is not currently forced on. Otherwise the value tells us
  83. // whether emulation is forced on.
  84. //
  85. CurrentNpxSetting = (rc == NO_ERROR) ? ForcedOn : 0;
  86. if(rc == ERROR_FILE_NOT_FOUND) {
  87. rc = NO_ERROR; // prevent bogus warning from being logged.
  88. }
  89. RegCloseKey(hKey);
  90. }
  91. if(rc != NO_ERROR) {
  92. SetuplogError(
  93. LogSevWarning,
  94. SETUPLOG_USE_MESSAGEID,
  95. MSG_LOG_UNABLE_TO_CHECK_NPX_SETTING,
  96. rc,
  97. 0,0);
  98. }
  99. //
  100. // For now set user's choice to the current setting.
  101. //
  102. UserNpxSetting = CurrentNpxSetting;
  103. }
  104. BOOL
  105. SetNpxEmulationState(
  106. VOID
  107. )
  108. /*++
  109. Routine Description:
  110. Set state of NPX emulation based on current state of global variables
  111. CurrentNpxSetting and UserNpxSetting.
  112. Arguments:
  113. None.
  114. Return Value:
  115. Boolean value indicating outcome.
  116. --*/
  117. {
  118. LONG rc;
  119. HKEY hKey;
  120. DWORD DataType;
  121. DWORD ForcedOn;
  122. DWORD DataSize;
  123. //
  124. // Nothing to to if the setting has not changed.
  125. //
  126. if(CurrentNpxSetting == UserNpxSetting) {
  127. return(TRUE);
  128. }
  129. rc = RegOpenKeyEx(HKEY_LOCAL_MACHINE,NpxEmulationKey,0,KEY_SET_VALUE,&hKey);
  130. if(rc == NO_ERROR) {
  131. rc = RegSetValueEx(
  132. hKey,
  133. NpxEmulationValue,
  134. 0,
  135. REG_DWORD,
  136. (PBYTE)&UserNpxSetting,
  137. sizeof(DWORD)
  138. );
  139. if(rc == NO_ERROR) {
  140. CurrentNpxSetting = UserNpxSetting;
  141. }
  142. RegCloseKey(hKey);
  143. }
  144. if(rc != NO_ERROR) {
  145. SetuplogError(
  146. LogSevWarning,
  147. SETUPLOG_USE_MESSAGEID,
  148. MSG_LOG_UNABLE_TO_SET_NPX_SETTING,
  149. rc,
  150. 0,0);
  151. }
  152. return(rc == NO_ERROR);
  153. }
  154. BOOL
  155. TestForDivideError(
  156. VOID
  157. )
  158. /*++
  159. Routine Description:
  160. Do a divide with a known divident/divisor pair, followed by
  161. a multiply to see if we get the right answer back.
  162. Arguments:
  163. None.
  164. Return Value:
  165. Boolean value indicating whether the computer exhibits the
  166. pentium fpu bug.
  167. --*/
  168. {
  169. DWORD pick;
  170. DWORD processmask;
  171. DWORD systemmask;
  172. DWORD i;
  173. BOOL rc;
  174. //
  175. // Assume no fpu bug.
  176. //
  177. rc = FALSE;
  178. //
  179. // Fetch the affinity mask, which is also effectively a list
  180. // of processors
  181. //
  182. GetProcessAffinityMask(GetCurrentProcess(),&processmask,&systemmask);
  183. //
  184. // Step through the mask, testing each cpu.
  185. // if any is bad, we treat them all as bad
  186. //
  187. for(i = 0; i < 32; i++) {
  188. pick = 1 << i;
  189. if(systemmask & pick) {
  190. SetThreadAffinityMask(GetCurrentThread(), pick);
  191. //
  192. // Call the critical test function
  193. //
  194. if(ms_p5_test_fdiv()) {
  195. rc = TRUE;
  196. break;
  197. }
  198. }
  199. }
  200. //
  201. // Reset affinity for this thread before returning.
  202. //
  203. SetThreadAffinityMask(GetCurrentThread(), processmask);
  204. return(rc);
  205. }
  206. /***
  207. * testfdiv.c - routine to test for correct operation of x86 FDIV instruction.
  208. *
  209. * Copyright (c) 1994, Microsoft Corporation. All rights reserved.
  210. *
  211. *Purpose:
  212. * Detects early steppings of Pentium with incorrect FDIV tables using
  213. * 'official' Intel test values. Returns 1 if flawed Pentium is detected,
  214. * 0 otherwise.
  215. *
  216. */
  217. int ms_p5_test_fdiv(void)
  218. {
  219. double dTestDivisor = 3145727.0;
  220. double dTestDividend = 4195835.0;
  221. double dRslt;
  222. _asm {
  223. fld qword ptr [dTestDividend]
  224. fdiv qword ptr [dTestDivisor]
  225. fmul qword ptr [dTestDivisor]
  226. fsubr qword ptr [dTestDividend]
  227. fstp qword ptr [dRslt]
  228. }
  229. return (dRslt > 1.0);
  230. }
  231. BOOL
  232. CALLBACK
  233. PentiumDlgProc(
  234. IN HWND hdlg,
  235. IN UINT msg,
  236. IN WPARAM wParam,
  237. IN LPARAM lParam
  238. )
  239. {
  240. NMHDR *NotifyParams;
  241. switch(msg) {
  242. case WM_INITDIALOG:
  243. //
  244. // Check the pentium.
  245. //
  246. CheckPentium();
  247. //
  248. // Set up default. If user setting is non-0, then some kind
  249. // of emulation is turned on (there are 2 possibilities).
  250. //
  251. CheckRadioButton(
  252. hdlg,
  253. IDC_RADIO_1,
  254. IDC_RADIO_2,
  255. UserNpxSetting ? IDC_RADIO_2 : IDC_RADIO_1
  256. );
  257. break;
  258. case WM_SIMULATENEXT:
  259. PropSheet_PressButton( GetParent(hdlg), PSBTN_NEXT);
  260. break;
  261. case WM_NOTIFY:
  262. NotifyParams = (NMHDR *)lParam;
  263. switch(NotifyParams->code) {
  264. case PSN_SETACTIVE:
  265. TESTHOOK(522);
  266. SetWizardButtons(hdlg,WizPagePentiumErrata);
  267. if (FlawedPentium || UiTest) {
  268. if(Unattended) {
  269. //
  270. // This call makes the dialog activate, meaning
  271. // we end up going through the PSN_WIZNEXT code below.
  272. //
  273. if (!UnattendSetActiveDlg(hdlg, IDD_PENTIUM))
  274. {
  275. break;
  276. }
  277. // Page becomes active, make page visible.
  278. SendMessage(GetParent(hdlg), WMX_BBTEXT, (WPARAM)FALSE, 0);
  279. } else {
  280. SetWindowLong(hdlg,DWL_MSGRESULT, 0);
  281. // Page becomes active, make page visible.
  282. SendMessage(GetParent(hdlg), WMX_BBTEXT, (WPARAM)FALSE, 0);
  283. }
  284. } else {
  285. SetWindowLong(hdlg,DWL_MSGRESULT,-1);
  286. }
  287. break;
  288. case PSN_WIZNEXT:
  289. case PSN_WIZFINISH:
  290. //
  291. // Fetch emulation state. If user wants emulation and emulation
  292. // was already turned on preserve the current emulation setting.
  293. // Otherwise use setting 1.
  294. //
  295. if(IsDlgButtonChecked(hdlg,IDC_RADIO_2)) {
  296. if(!UserNpxSetting) {
  297. UserNpxSetting = 1;
  298. }
  299. } else {
  300. UserNpxSetting = 0;
  301. }
  302. break;
  303. default:
  304. break;
  305. }
  306. break;
  307. default:
  308. return(FALSE);
  309. }
  310. return(TRUE);
  311. }