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.

6918 lines
167 KiB

  1. /*++
  2. Copyright (c) 1999-2001 Microsoft Corporation. All Rights Reserved.
  3. Module Name:
  4. rt.c
  5. Abstract:
  6. Author:
  7. Joseph Ballantyne
  8. Environment:
  9. Kernel Mode
  10. Revision History:
  11. --*/
  12. // We use inline functions heavily. Set up the compiler
  13. // to use them.
  14. #pragma inline_recursion(off)
  15. #pragma inline_depth(255)
  16. // Some functions MUST be inlined in order for the code to
  17. // work correctly. Force the compiler to report errors for
  18. // functions that are marked __forceinline that are not inlined.
  19. #pragma warning( error: 4714 )
  20. #include "common.h"
  21. #pragma LOCKED_CODE
  22. #pragma LOCKED_DATA
  23. #include "x86.h"
  24. #include "cpu.h"
  25. #include "msr.h"
  26. #include <rt.h>
  27. #include "rtp.h"
  28. #ifdef UNDER_NT
  29. #include "rtinfo.h"
  30. #else
  31. #include <rtinfo.h>
  32. #endif
  33. #include "apic.h"
  34. #include "irq.h"
  35. #include "rtexcept.h"
  36. #include "log.h"
  37. #ifndef UNDER_NT
  38. #include <vmm.h>
  39. #include <vwin32.h>
  40. #include <ntkern.h>
  41. #include <vpowerd.h>
  42. #define PAGEFRMINST 0x20000000
  43. #ifdef WAKE_EVERY_MS
  44. #include <vtd.h>
  45. #endif
  46. #endif
  47. #pragma LOCKED_CODE
  48. #pragma LOCKED_DATA
  49. typedef struct {
  50. ULONGLONG Mark;
  51. ULONGLONG Delta;
  52. } YIELDTIME, *PYIELDTIME;
  53. #pragma pack(push,2)
  54. typedef struct threadstate {
  55. struct threadstate *next;
  56. struct threadstate *previous;
  57. WORD ds;
  58. WORD es;
  59. WORD fs;
  60. WORD gs;
  61. ULONG ecx;
  62. ULONG edx;
  63. ULONG ebx;
  64. ULONG ebp;
  65. ULONG esi;
  66. ULONG edi;
  67. ULONG esp;
  68. WORD ss;
  69. WORD state;
  70. ULONG data;
  71. ULONG irql;
  72. ThreadStats *Statistics;
  73. HANDLE ThreadHandle;
  74. ULONGLONG Mark;
  75. ULONGLONG Delta;
  76. PVOID FloatState;
  77. PHANDLE pThreadHandle;
  78. PULONG StackBase;
  79. PVOID FloatBase;
  80. } ThreadState;
  81. typedef struct {
  82. ULONG esp;
  83. WORD ss;
  84. } Stack;
  85. #pragma pack(pop)
  86. #define CATCH_INTERRUPTS_DISABLED_TOO_LONG 1
  87. #define USEMACROS 1
  88. #define LOCALSTACKSIZE 256
  89. #define FLOATSTATESIZE 512
  90. #define FXALIGN 16
  91. #define MAXAPICERRORHISTOGRAM 0xff
  92. #define MINIMUMCYCLECOUNT 50
  93. #ifdef WAKE_EVERY_MS
  94. ULONG WakeCpuFromC2C3EveryMs=FALSE;
  95. #endif
  96. #ifdef CATCH_INTERRUPTS_DISABLED_TOO_LONG
  97. extern PBOOLEAN KdEnteredDebugger;
  98. ULONG NmiInterruptCount=0;
  99. ULONG_PTR OriginalWindowsNmiHandler=0;
  100. LONG MaxUsecWithInterruptsDisabled=1500;
  101. #endif
  102. ULONGLONG RtShutdownTime=0;
  103. ULONGLONG lasttime=0;
  104. ULONG LocalApicSpuriousInterruptCount=0;
  105. ULONG LocalApicErrorInterruptCount=0;
  106. ULONG ApicErrorHistogram[MAXAPICERRORHISTOGRAM+1];
  107. ULONG RtCpuCyclesPerUsec=0;
  108. ULONG RtSystemBusCyclesPerUsec=0;
  109. volatile ULONG RtCpuAllocatedPerMsec=0;
  110. ULONG RtPsecPerCpuCycle;
  111. ULONG RtRunning=0;
  112. ULONG RtLastUniqueThreadHandle=0;
  113. ID OriginalNmiVector;
  114. ID OriginalMaskableVector;
  115. ID OriginalApicErrorVector;
  116. ID OriginalApicSpuriousVector;
  117. ULONG LastTPR=0;
  118. ULONG SwitchRtThreadReenterCount=0;
  119. ULONGLONG threadswitchcount=0;
  120. ULONGLONG lastthreadswitchtime=0;
  121. ThreadState *windowsthread=NULL;
  122. ThreadState *currentthread=NULL;
  123. ThreadState *lastthread=NULL;
  124. ThreadState * volatile RtDeadThreads=NULL;
  125. ULONG RtThreadCount=0;
  126. ULONG activefloatthreadcount=0;
  127. ULONG RtpForceAtomicHoldoffCount=0;
  128. ULONG RtpTransferControlHoldoffCount=0;
  129. KSPIN_LOCK RtThreadListSpinLock=0;
  130. ULONG PerformanceInterruptState=MASKPERF0INT;
  131. PKIRQL pCurrentIrql=NULL;
  132. #ifdef MASKABLEINTERRUPT
  133. ULONG InjectWindowsInterrupt=0;
  134. SPTR HandleWindowsInterrupt={0,0x28};
  135. ULONG InjectedInterruptCount=0;
  136. ULONG EnabledInterrupts=0;
  137. ULONG OriginalIrql=0;
  138. #endif
  139. ULONG LastWindowsCR0=0;
  140. ULONG NextCR0=0;
  141. WORD RtRing3Selector=0;
  142. WORD RtExecCS=0;
  143. WORD RtThreadCS=0;
  144. WORD RealTimeDS=0;
  145. WORD RealTimeSS=0;
  146. WORD OriginalDS=0;
  147. #ifdef GUARD_PAGE
  148. WORD RtExecTSS=0;
  149. extern TSS RtTss;
  150. #endif
  151. ULONG loopcount=0;
  152. ULONG SendPendingCount=0;
  153. ULONG SendPendingLoopCount=0;
  154. ULONG TransferControlReMaskCount=0;
  155. Stack RealTimeStack;
  156. ULONG LocalStack[LOCALSTACKSIZE];
  157. #ifdef WAKE_EVERY_MS
  158. ULONG
  159. SetTimerResolution (
  160. ULONG ms
  161. )
  162. /*++
  163. Routine Description:
  164. Arguments:
  165. Return Value:
  166. --*/
  167. {
  168. ASSERT ( ms != 0 );
  169. // Set the new resolution.
  170. #ifdef UNDER_NT
  171. return (ExSetTimerResolution( ms*10000, TRUE) + 5000)/10000;
  172. #else
  173. __asm mov eax, ms
  174. VxDCall(VTD_Begin_Min_Int_Period);
  175. __asm jnc done
  176. __asm xor eax,eax
  177. done:
  178. ;
  179. #endif
  180. }
  181. VOID
  182. ReleaseTimerResolution (
  183. ULONG ms
  184. )
  185. /*++
  186. Routine Description:
  187. Arguments:
  188. Return Value:
  189. --*/
  190. {
  191. ASSERT ( ms != 0 );
  192. #ifdef UNDER_NT
  193. ExSetTimerResolution( ms*10000, FALSE);
  194. #else
  195. __asm mov eax,ms
  196. VxDCall(VTD_End_Min_Int_Period);
  197. #if DEBUG
  198. __asm jnc ok
  199. dprintf((QDBG"Error releasing minimum interrupt period!"));
  200. Trap();
  201. ok:
  202. ;
  203. #endif
  204. #endif
  205. }
  206. #endif
  207. #if 0
  208. // This doesn't work. New Intel machines only write the bottom 32 bits of the count
  209. // and clear the top 32 bits - so setting the count is not useful except to set it
  210. // to zero.
  211. VOID __inline WriteCycleCounter(LONGLONG Count)
  212. {
  213. WriteIntelMSR(0x80000000+0x10, Count);
  214. }
  215. #endif
  216. #pragma warning ( disable : 4035 )
  217. #ifdef MASKABLEINTERRUPT
  218. VOID
  219. _fastcall
  220. WrapKfLowerIrql (
  221. KIRQL Irql
  222. )
  223. {
  224. KeLowerIrql(Irql);
  225. }
  226. #endif
  227. #ifdef GUARD_PAGE
  228. ULONG
  229. __cdecl
  230. CommitPages (
  231. ULONG page,
  232. ULONG npages,
  233. ULONG hpd,
  234. ULONG pagerdata,
  235. ULONG flags
  236. )
  237. /*++
  238. Routine Description:
  239. Arguments:
  240. Return Value:
  241. --*/
  242. {
  243. __asm {
  244. push flags
  245. push pagerdata
  246. push hpd
  247. push npages
  248. push page
  249. VMMCall( _PageCommit )
  250. __asm add esp, 0x14
  251. }
  252. }
  253. PVOID
  254. __cdecl
  255. ReservePages (
  256. ULONG page,
  257. ULONG npages,
  258. ULONG flags
  259. )
  260. /*++
  261. Routine Description:
  262. Arguments:
  263. Return Value:
  264. --*/
  265. {
  266. __asm {
  267. push flags
  268. push npages
  269. push page
  270. VMMCall( _PageReserve )
  271. __asm add esp, 12
  272. }
  273. }
  274. PVOID
  275. __cdecl
  276. FreePages (
  277. PVOID hmem,
  278. DWORD flags
  279. )
  280. /*++
  281. Routine Description:
  282. Arguments:
  283. Return Value:
  284. --*/
  285. {
  286. __asm {
  287. push flags
  288. push hmem
  289. VMMCall( _PageFree )
  290. __asm add esp, 8
  291. }
  292. }
  293. #endif
  294. #pragma warning ( default : 4035 )
  295. #if 0
  296. NTSTATUS CreateReadOnlyStatisticsPage(ThreadState *ThreadState)
  297. {
  298. #ifndef UNDER_NT
  299. ULONG CR3;
  300. static ULONG LastCR3=0;
  301. static ULONG PageDirectory=0;
  302. ULONG PageTable;
  303. ThreadStats *readonlystats;
  304. // Get current CR3 value.
  305. CR3=GetCR3();
  306. // If different from previous, we must map the page directory.
  307. if (CR3!=LastCR3) {
  308. if (LastCR3) {
  309. // CR3 changed - after we started up. This should not normally happen.
  310. Trap();
  311. }
  312. // Map the page directory. We must redo this when CR3 changes. In that case
  313. // we will waste the previously mapped directory, but then again, that should
  314. // never happen.
  315. PageDirectory=(PULONG)MapPhysicalToLinear((PVOID)CR3, PROCPAGESIZE, 0);
  316. if (PageDirectory==(-1)) {
  317. return STATUS_UNSUCCESSFUL;
  318. }
  319. // Remember which page directory we have currently mapped.
  320. LastCR3=CR3;
  321. }
  322. // Now get a page that we can map for a read only copy of the statistics.
  323. readonlystats=ReservePages(PR_SYSTEM, 1, PR_FIXED);
  324. if (readonlystats==(-1)) {
  325. return STATUS_UNSUCCESSFUL;
  326. }
  327. // Now get a linear address for the page table containing this page.
  328. ReadOnlyStatisticsPageTable=MapPhysicalToLinear((PVOID)((PageDirectory[(ULONG)(readonlystats)>>22])&(~(PROCPAGESIZE-1))), PROCPAGESIZE, 0);
  329. // Make our page a read only page mapped to same physical page as the read/write
  330. // statistics.
  331. return readonlystats;
  332. #else
  333. // This function is not yet implemented. For now punt.
  334. return STATUS_NOT_IMPLEMENTED;
  335. #endif
  336. }
  337. #endif
  338. NTSTATUS
  339. HookInterrupt (
  340. ULONG index,
  341. ID *originalvector,
  342. VOID (* handler)(VOID)
  343. )
  344. {
  345. IDT systemidt;
  346. ID newvector;
  347. SaveAndDisableMaskableInterrupts();
  348. // Get the IDT.
  349. SaveIDT(systemidt);
  350. if ( systemidt.limit < (index+1)*8-1 ) {
  351. Trap();
  352. RestoreMaskableInterrupts();
  353. return STATUS_UNSUCCESSFUL;
  354. }
  355. // Save the current handler.
  356. *originalvector=*(ID *)(systemidt.base+index*8);
  357. // Blast in our new idt entry.
  358. newvector.highoffset=(WORD)((DWORD)handler>>16);
  359. newvector.flags=0x8e00;
  360. newvector.selector=RtExecCS;
  361. newvector.lowoffset=(WORD)handler;
  362. *(ID *)(systemidt.base+index*8)=newvector;
  363. RestoreMaskableInterrupts();
  364. return STATUS_SUCCESS;
  365. }
  366. // This routine takes at least 10 cycles on a Pentium.
  367. #define SaveThreadState() \
  368. __asm { \
  369. __asm sub esp,4 /*ds already saved */ \
  370. __asm push es \
  371. __asm push fs \
  372. __asm push gs \
  373. __asm pushad \
  374. }
  375. // This routine takes at least 18 cycles on a Pentium.
  376. #define RestoreThreadState() \
  377. __asm { \
  378. __asm popad \
  379. __asm pop gs \
  380. __asm pop fs \
  381. __asm pop es \
  382. __asm pop ds \
  383. }
  384. #define AllocateStackForFPState() \
  385. __asm { \
  386. __asm sub esp,108 \
  387. }
  388. #define ReleaseStackForFPState() \
  389. __asm { \
  390. __asm add esp,108 \
  391. }
  392. #define fxsave_eax __asm _emit 0xf __asm _emit 0xae __asm _emit 0x0
  393. #define fxrstor_eax __asm _emit 0xf __asm _emit 0xae __asm _emit 0x8
  394. // This routine takes at least 125 cycles on a Pentium.
  395. VOID __inline SaveThreadFloatState(PVOID FloatState)
  396. {
  397. __asm {
  398. test dword ptr CPUFeatures,FXSR
  399. mov eax,FloatState
  400. jnz xsave
  401. fnsave [eax]
  402. jmp savedone
  403. xsave:
  404. fxsave_eax
  405. savedone:
  406. }
  407. }
  408. // This routine takes at least 71 cycles on a Pentium.
  409. VOID __inline RestoreThreadFloatState(PVOID FloatState)
  410. {
  411. __asm {
  412. test dword ptr CPUFeatures,FXSR
  413. mov eax,FloatState
  414. jnz xrestore
  415. frstor [eax]
  416. jmp restoredone
  417. xrestore:
  418. fxrstor_eax
  419. restoredone:
  420. }
  421. }
  422. #pragma warning ( disable : 4035 )
  423. ULONG Get_FS(VOID)
  424. {
  425. #ifndef UNDER_NT
  426. Load_FS;
  427. #endif
  428. __asm {
  429. xor eax,eax
  430. mov ax,fs
  431. #ifdef UNDER_NT
  432. cmp eax,0x30
  433. jz ok
  434. int 3
  435. ok:
  436. #endif
  437. }
  438. }
  439. #pragma warning ( default : 4035 )
  440. // 1 cycle
  441. #define LoadThreadStatePointer() \
  442. __asm mov eax, currentthread
  443. // 2 cycles
  444. #define SaveThreadStack() \
  445. __asm { \
  446. __asm mov [eax]ThreadState.esp,esp \
  447. __asm mov [eax]ThreadState.ss,ss \
  448. }
  449. // 8 cycles
  450. #define RestoreThreadStack() \
  451. __asm { \
  452. __asm lss esp,[eax]ThreadState.esp \
  453. }
  454. #define StopPerformanceCounters() \
  455. __asm { \
  456. __asm mov eax, STOPPERFCOUNTERS \
  457. __asm xor edx, edx \
  458. __asm mov ecx, EVENTSELECT0 \
  459. __asm _emit 0x0f \
  460. __asm _emit 0x30 \
  461. }
  462. #define StartPerformanceCounters() \
  463. __asm { \
  464. __asm mov eax,EnablePerfCounters \
  465. __asm xor edx,edx \
  466. __asm mov ecx, EVENTSELECT0 \
  467. __asm _emit 0x0f \
  468. __asm _emit 0x30 \
  469. }
  470. #define TurnOnPerformanceCounters() \
  471. __asm { \
  472. __asm test cs:EnablePerfCounters, 0xffffffff \
  473. __asm jz noperf \
  474. __asm push eax \
  475. __asm push edx \
  476. __asm push ecx \
  477. __asm xor edx, edx \
  478. __asm mov ecx, cs:EVENTSELECT0 \
  479. __asm mov eax, cs:EnablePerfCounters \
  480. __asm _emit 0x0f \
  481. __asm _emit 0x30 \
  482. __asm pop ecx \
  483. __asm pop edx \
  484. __asm pop eax \
  485. __asm noperf: \
  486. }
  487. // We need a more advanced function for on the fly programming.
  488. // Using this function for programming counters that are moving will
  489. // NOT keep them syncronized.
  490. // Note that when we implement that and compensate for the instruction
  491. // count to keep the counters syncronized, we need to make sure we
  492. // do NOT take counts between zero and OVERHEAD instructions and make them
  493. // NEGATIVE and thus generate interrupts too soon.
  494. // For counters that are both moving we should subtract the overhead. For
  495. // counters that are stopped we should NOT. For mismatched counters there
  496. // is no intelligent thing we can do. We will not subtract overhead.
  497. VOID SetTimeLimit(LONG cycles, LONG instructions)
  498. {
  499. ULONG OldPerfIntState;
  500. // Disable maskable and the scheduler interrupts.
  501. SaveAndDisableMaskableInterrupts();
  502. SaveAndDisablePerformanceCounterInterrupt(&OldPerfIntState);
  503. //WriteIntelMSR(INSTRUCTIONCOUNT, -instructions);
  504. WriteIntelMSR(CYCLECOUNT,-cycles);
  505. #if DEBUG
  506. // Now if the counters are disabled, then verify that they are set correctly.
  507. // For we only validate the bottom 32 bits since on Intel P6 processors that
  508. // is all that is used to program the counts. This validation code should
  509. // work correctly on all P6 and K7 processors.
  510. if (((ReadIntelMSR(CYCLECOUNT)^(ULONGLONG)-cycles)&PERFCOUNTMASK)) {
  511. Trap();
  512. }
  513. // We have to handle AMD and Intel differently, since on Intel, the enable
  514. // bit in perf counter 0 controls ALL of the counters, while on AMD, they did
  515. // it differently and gave each counter its own enable bit. The Intel way
  516. // makes it possible for you to turn on and off all of the counters in
  517. // one instruction which is very important if you want to syncronize the
  518. // results of multiple counters to the same enabled/disabled time period.
  519. // Actually, AMDs design could cause me problems - since I may not
  520. // want to have to turn on and off every counter individually. It certainly
  521. // does make perfect syncronization of multiple counters impossible.
  522. // One VERY nice thing about AMD's design is that you can use the counters
  523. // independently: you don't HAVE to own counter0 to be able to use counter1.
  524. // That makes sharing different counters between different clients possible.
  525. /*
  526. {
  527. ULONG Counter1Enable=EVENTSELECT0;
  528. if (CPUManufacturer==AMD) {
  529. Counter1Enable=EVENTSELECT1;
  530. }
  531. if (!(ReadIntelMSR(Counter1Enable)&PERFCOUNTERENABLED) &&
  532. ((ReadIntelMSR(INSTRUCTIONCOUNT)^(ULONGLONG)-instructions)&PERFCOUNTMASK)) {
  533. Trap();
  534. }
  535. }
  536. */
  537. #endif
  538. // Restore interrupt state.
  539. RestorePerformanceCounterInterrupt(OldPerfIntState);
  540. RestoreMaskableInterrupts();
  541. }
  542. #define SaveEAX() \
  543. __asm push eax
  544. #define RestoreEAX() \
  545. __asm pop eax
  546. // 19 cycles
  547. #define SignalRtExceptions() \
  548. __asm { \
  549. __asm _emit 0x0f __asm _emit 0x20 __asm _emit 0xe0 /* __asm mov eax,cr4 */ \
  550. __asm or eax,4 \
  551. __asm _emit 0x0f __asm _emit 0x22 __asm _emit 0xe0 /* __asm mov cr4,eax */ \
  552. }
  553. // 7 cycles
  554. #define LoadRtDS() \
  555. __asm { \
  556. __asm mov ax,ds \
  557. __asm shl eax,16 \
  558. __asm mov ax,cs:RealTimeDS \
  559. __asm mov ds,ax \
  560. }
  561. // 2 cycles
  562. #define HoldOriginalDS() \
  563. __asm { \
  564. __asm shr eax,16 \
  565. __asm mov OriginalDS,ax \
  566. }
  567. // 2 cycles
  568. #define SaveOriginalDS() \
  569. __asm { \
  570. __asm mov bx,OriginalDS \
  571. __asm mov [eax]ThreadState.ds,bx \
  572. }
  573. // 3 cycles
  574. #define RestoreOriginalDS() \
  575. __asm { \
  576. __asm mov ds,[eax]ThreadState.ds \
  577. }
  578. #define SetupStack() \
  579. __asm { \
  580. __asm lss esp,RealTimeStack \
  581. __asm mov ebp,esp \
  582. __asm sub esp,__LOCAL_SIZE \
  583. /* The next 2 lines are CRITICAL. Without them, string instructions fault! */ \
  584. __asm mov es,RealTimeDS \
  585. __asm cld \
  586. }
  587. // 3 cycles
  588. #define SaveSegmentState() \
  589. __asm { \
  590. __asm mov [eax]ThreadState.es,es \
  591. __asm mov [eax]ThreadState.fs,fs \
  592. __asm mov [eax]ThreadState.gs,gs \
  593. }
  594. // 9 cycles
  595. #define RestoreSegmentState() \
  596. __asm { \
  597. __asm mov es,[eax]ThreadState.es \
  598. __asm mov fs,[eax]ThreadState.fs \
  599. __asm mov gs,[eax]ThreadState.gs \
  600. }
  601. // ~3 cycles
  602. #define SaveRegisterState() \
  603. __asm { \
  604. __asm mov [eax]ThreadState.ecx, ecx \
  605. __asm mov [eax]ThreadState.edx, edx \
  606. __asm mov [eax]ThreadState.ebx, ebx \
  607. __asm mov [eax]ThreadState.ebp, ebp \
  608. __asm mov [eax]ThreadState.esi, esi \
  609. __asm mov [eax]ThreadState.edi, edi \
  610. }
  611. // ~3 cycles
  612. #define RestoreRegisterState() \
  613. __asm { \
  614. __asm mov ecx,[eax]ThreadState.ecx \
  615. __asm mov edx,[eax]ThreadState.edx \
  616. __asm mov ebx,[eax]ThreadState.ebx \
  617. __asm mov ebp,[eax]ThreadState.ebp \
  618. __asm mov esi,[eax]ThreadState.esi \
  619. __asm mov edi,[eax]ThreadState.edi \
  620. }
  621. VOID RemoveRtThread(ThreadState *thread)
  622. {
  623. // Now make sure the thread is not holding any spinlocks. It is an
  624. // error to destroy a realtime thread that is holding any spinlocks.
  625. // Note that we MUST atomically check the spinlock count and remove
  626. // the thread from the list of runnable threads - otherwise we could
  627. // think the thread is not holding a spinlock and get switched out and
  628. // have it acquire one just before we kill it.
  629. // Unhook thread from the list.
  630. thread->next->previous=thread->previous;
  631. thread->previous->next=thread->next;
  632. if (thread->FloatState!=NULL) {
  633. activefloatthreadcount--;
  634. }
  635. // Update our RT thread count.
  636. RtThreadCount--;
  637. // Mark the thread as dead.
  638. //thread->state=DEAD;
  639. // Now mask the realtime scheduler interrupt if the thread count is 1.
  640. if (RtThreadCount==1) {
  641. WriteAPIC(APICTIMER, ApicTimerVector|MASKED|PERIODIC);
  642. }
  643. // Make its cycles available.
  644. RtCpuAllocatedPerMsec-=(ULONG)(thread->Statistics->Duration/(thread->Statistics->Period/MSEC));
  645. }
  646. ULONGLONG
  647. OriginalRtTime (
  648. VOID
  649. )
  650. {
  651. ULONGLONG time;
  652. time=ReadCycleCounter();
  653. // Make sure time never goes backwards. Trap if it does.
  654. if ((LONGLONG)(time-lasttime)<0) {
  655. //Trap(); // BUGBUG THIS IS HITTING FIND OUT WHY!!!
  656. }
  657. lasttime=time;
  658. time*=USEC/RtCpuCyclesPerUsec;
  659. if (!time) {
  660. time--;
  661. }
  662. return time;
  663. }
  664. ULONGLONG
  665. FastRtTime (
  666. VOID
  667. )
  668. {
  669. ULONGLONG time;
  670. time=ReadCycleCounter();
  671. lasttime=time;
  672. time*=RtPsecPerCpuCycle;
  673. if (!time) {
  674. time--;
  675. }
  676. return time;
  677. }
  678. ULONGLONG
  679. RtTime (
  680. VOID
  681. )
  682. {
  683. ULONGLONG CurrentRead, LastRead, PreviousValue;
  684. PreviousValue=0;
  685. // First atomically grab the last time logged.
  686. LastRead=InterlockedCompareExchange64(&lasttime, PreviousValue, PreviousValue);
  687. // Now read the timestamp counter.
  688. CurrentRead=ReadCycleCounter();
  689. // Make sure time never goes backwards. Trap if it does.
  690. if ((LONGLONG)(CurrentRead-LastRead)<0) {
  691. Break();
  692. }
  693. // Save this read of the timestamp counter. If the compare exchange fails,
  694. // then a higher priority task has interrupted us and already updated the
  695. // time, so just report the time it logged.
  696. PreviousValue=InterlockedCompareExchange64(&lasttime, CurrentRead, LastRead);
  697. if (PreviousValue!=LastRead) {
  698. CurrentRead=PreviousValue;
  699. }
  700. // Convert the timestamp counter reading from cycles into picoseconds.
  701. // Make sure we never return a time of zero.
  702. CurrentRead*=RtPsecPerCpuCycle;
  703. if (CurrentRead==0) {
  704. CurrentRead--;
  705. }
  706. return CurrentRead;
  707. }
  708. // This is the local apic spurious interrupt handler. All we do in this
  709. // handler is increment a count of the number of spurious interrupts, and
  710. // return. This routine should NOT EOI the apic.
  711. VOID
  712. __declspec(naked)
  713. RtpLocalApicSpuriousHandler (
  714. VOID
  715. )
  716. {
  717. __asm {
  718. push ds
  719. mov ds, cs:RealTimeDS
  720. lock inc LocalApicSpuriousInterruptCount
  721. pop ds
  722. }
  723. Return();
  724. }
  725. // This routine will be called when local apic errors are unmasked and
  726. // occur.
  727. // For now all we do is increment a count and
  728. // We may use this in the future to help determine if interrupts are staying
  729. // masked for too long. This we can do by simply forcing an error while in
  730. // the SwitchRealTimeThreads routine while interrupts are off, and then seeing
  731. // if when we get back into that routine, this Error handler has hit or not.
  732. // If we hit this handler then interrupts were definitely enabled for at least
  733. // part of the time since we left the SwitchRealTimeThreads routine. If we didn't
  734. // hit this handler then interrupts MAY have been disabled the whole time. It is possible
  735. // that we were not the highest priority interrupt when interrupts were enabled and
  736. // some other handler was called. So, not getting called does NOT mean that interrupts
  737. // were disabled the whole time. It CAN mean that - and it ussually will mean that.
  738. VOID
  739. __declspec(naked)
  740. RtpLocalApicErrorHandler (
  741. VOID
  742. )
  743. {
  744. __asm {
  745. push ds
  746. mov ds, cs:RealTimeDS
  747. lock inc LocalApicErrorInterruptCount
  748. pop ds
  749. }
  750. Trap();
  751. Return();
  752. }
  753. VOID __declspec(naked) SwitchRealTimeThreads(VOID)
  754. {
  755. //LONG i;
  756. // Paranoia: Make sure we are not being reentered.
  757. __asm {
  758. push ds
  759. mov ds, cs:RealTimeDS
  760. inc SwitchRtThreadReenterCount
  761. cmp SwitchRtThreadReenterCount, 1
  762. pop ds
  763. jz notreentered
  764. int 3
  765. notreentered:
  766. }
  767. #ifdef DEBUG
  768. // Paranoia: Make sure interrupts are disabled.
  769. __asm {
  770. pushfd
  771. test dword ptr[esp], IF
  772. jz intsdisabled
  773. int 3
  774. and dword ptr[esp], ~(IF)
  775. intsdisabled:
  776. popfd
  777. }
  778. #endif
  779. // Now save the Windows IDT properly so that any exceptions that hit
  780. // after we switch IDTs will be handled properly. If we do not do
  781. // this BEFORE switching IDTs, then any exceptions that occur between
  782. // the switch and the saving of the Windows IDT state could make an
  783. // OLD windows IDT get loaded in the exception handler. Really NOT
  784. // a good idea.
  785. __asm {
  786. // Note that we do NOT use the CS test here, since we may have
  787. // come in from the debugger and that might have switched our
  788. // CS, although it should NOT have. If it does, it will also
  789. // hose all of our checks in ntkern and vmm for whether we are
  790. // running a realtime thread or not. This is a faster test
  791. // anyway.
  792. push eax
  793. mov eax, cs:currentthread
  794. cmp eax, cs:windowsthread
  795. jnz notwindows
  796. // Get our FLAT selector into DS so we can write memory.
  797. push ds
  798. mov ds, cs:RealTimeDS
  799. #ifdef MASKABLEINTERRUPT
  800. // The very first thing we do is to disable all maskable interrupts.
  801. // We do this as early as possible in this routine - since we need
  802. // to prevent normal PIC interrupts from getting queued up in the
  803. // processor. They will fire when we return control to the realtime
  804. // threads and will GP fault. We can currently queue up and defer
  805. // one, but ONLY one.
  806. // The fundamental problem we are trying to solve is that there is a
  807. // window between when the processor masks interrupts when it is
  808. // processing this interrupt through the interrupt gate, and this next
  809. // snippet of code - where we disable the external interrupts. This
  810. // is only a problem if we run the realtime threads with interrupts
  811. // enabled and use a maskable interrupt to switch between them.
  812. // Because of that Window we may ALWAYS have 1 or more interrupts pended
  813. // inside the CPU that masking the local APIC interrupt will have
  814. // no effect on.
  815. // Note that we only need to mask external interrupts and then flush
  816. // out any pending ones IF we are coming in from windows AND we are
  817. // NOT coming in on an rtptransfercontrol. If the external interrupts
  818. // are already masked then we ABSOLUTELY DO NOT want to reenable
  819. // interrupts - since we are trying to make the transition from
  820. // transfer control all the way through this routine COMPLETELY ATOMIC.
  821. // IF and ONLY IF, the external interrupts are currently ENABLED, then
  822. // we will mask them, and reenable interrupts temporarily. This
  823. // technique functions like an airlock - where first all interrupts
  824. // are masked in the processor, but some may get stuck inside pending.
  825. // Then we close the outside door - by masking external interrupts at
  826. // the apic. Then we flush anything left waiting inside through by
  827. // enabling interrupts while the external interrupts are disabled,
  828. // then we close the inside door again by masking interrupts.
  829. mov eax, ApicIntrInterrupt
  830. test dword ptr[eax], MASKED
  831. jnz skippendinginterruptfix
  832. // If we get here, then interrupts need to be masked at the apic and we
  833. // need to flush through any interrupts pending in the processor.
  834. or dword ptr[eax], MASKED
  835. // The second line of defense is to REENABLE interrupts after having
  836. // turned them off! This will allow any interrupts that are queued
  837. // up to fire. We do this ONLY if we are leaving windows and are starting
  838. // to run realtime threads. We also only do this if we MUST. It is
  839. // likely that we will need to do this, because the processor can
  840. // queue up multiple interrupts - and it does handle some with higher
  841. // priority than others. So, IF the local apic interrupts have higher
  842. // priority than the external interrupt interrupt, then we may still
  843. // have interrupts pending inside the processor that will hit when we
  844. // popfd in either RtpTransferControl, or when we iret to a real time
  845. // thread from this routine. This fix should prevent that from ever
  846. // happenning.
  847. // Before we turn on interrupts however, we make sure that we hold
  848. // off any processing of DPCs. We hold off DPC processing until
  849. // we are switching back to Windows. This should help reduce or ideally
  850. // eliminate reentrancy in this routine.
  851. // The code between enableok and irqlok is ABSOLUTELY NOT reentrant. So we
  852. // must crash and burn if we try to reenter it.
  853. inc EnabledInterrupts
  854. cmp EnabledInterrupts, 1
  855. jz enableok
  856. int 3
  857. enableok:
  858. mov eax, pCurrentIrql
  859. movzx eax, byte ptr[eax]
  860. mov OriginalIrql, eax
  861. cmp eax, DISPATCH_LEVEL
  862. jge irqlok
  863. mov eax, pCurrentIrql
  864. mov byte ptr[eax], DISPATCH_LEVEL
  865. irqlok:
  866. sti
  867. nop
  868. nop
  869. nop
  870. nop
  871. cli
  872. skippendinginterruptfix:
  873. #endif
  874. // If we get here, then we need to save off the current IDT so
  875. // that we restore the proper IDT in our RT exec exception handlers.
  876. // We MUST do this BEFORE switching IDTs. Otherwise our exception
  877. // handlers may restore the WRONG windows IDT.
  878. sidt WindowsIDT
  879. pop ds
  880. notwindows:
  881. pop eax
  882. }
  883. // We MUST have saved away the current windows idt before we make this
  884. // switch. Otherwise the realtime executive exception handlers may
  885. // load an INCORRECT windows IDT.
  886. LoadIDT(RtExecIDT);
  887. __asm {
  888. push ds
  889. mov ds, cs:RealTimeDS
  890. }
  891. SaveIDT(DebugIDT); // Make sure we put back correct IDT in exception handlers.
  892. __asm {
  893. pop ds
  894. }
  895. SaveEAX();
  896. LoadRtDS();
  897. HoldOriginalDS();
  898. LoadThreadStatePointer();
  899. SaveSegmentState();
  900. SaveRegisterState();
  901. SaveOriginalDS();
  902. SaveThreadStack();
  903. SetupStack();
  904. StopPerformanceCounters();
  905. // Save Irql for thread we are leaving.
  906. // To do this we directly read the memory in ntkern that holds current irql.
  907. currentthread->irql=*pCurrentIrql;
  908. #if DEBUG
  909. //*ApicTimerInterrupt=ApicTimerVector|MASKED|PERIODIC;
  910. #endif
  911. // After this point it is safe to run essentially any code we want.
  912. // The stack is setup so straight c will work properly, and the
  913. // scheduler interrupt is turned off.
  914. // Note that we should check for reentrancy on this interrupt. We can
  915. // do that really easily by having a separate IDT for the rt executive.
  916. // We load that when we enter this routine, we load the windows IDT when
  917. // we exit this routine and return to windows, and we load the rt threads
  918. // IDT when we exit this routine running a real time thread.
  919. // That will make it easy to isolate exceptions caused by the RT executive
  920. // versus exceptions caused by real time threads.
  921. //Trap();
  922. // Make sure that we do not have any ISR in APIC other than our own.
  923. // Make sure no IRR in APIC - otherwise we have been held off.
  924. // Check for cases when we have stopped in the debugger on an int 3 in
  925. // a realtime thread and have loaded the windows idt.
  926. // Nasty case when we iret back from switchrealtime threads to an int 3 itself
  927. // should be considered
  928. // we have to make absolutely sure that no interrupts get processed while
  929. // we are running the realtime thead. In that case ints may stay disabled
  930. // the whole time until after the windows idt is loaded.
  931. if (currentthread!=windowsthread) {
  932. #ifdef MASKABLEINTERRUPT
  933. // Make sure that interrupts are enabled on this realtime thread. Again
  934. // they may not be if we hit an int 3 and transfered control to the
  935. // debugger. If they are disabled, then reenable them for the next
  936. // switch into that thread.
  937. // Trap in debug if they are disabled and we did not log an int 3 hit in
  938. // the code.
  939. // First make sure that we got here on an RtpTransferControl.
  940. if (*(WORD *)((*(ULONG *)(currentthread->esp+EIPRETURNADDRESSOFFSET*sizeof(ULONG)))-2)==(0xcd|(TRANSFERCONTROLIDTINDEX<<8))) {
  941. // We got here on an RtpTransferControl. Check the flags that got pushed
  942. // in that routine before the CLI, so that we check the real state of the
  943. // rt thread's interrupt flag.
  944. if (((ULONG *)(currentthread->esp))[RTPTRANSFERCONTROLEFLAGSOFFSET]&IF) {
  945. // Realtime thread has interrupts ENABLED!
  946. // We better not think that we hit an int 3.
  947. #ifdef DEBUG
  948. if (HitInt3InRtThread) {
  949. Trap();
  950. }
  951. #endif
  952. }
  953. else {
  954. // Realtime thread has interrupts DISABLED!
  955. // Reenable them, and make sure we hit an int 3.
  956. ((ULONG *)(currentthread->esp))[RTPTRANSFERCONTROLEFLAGSOFFSET]|=IF;
  957. #ifdef DEBUG
  958. if (!HitInt3InRtThread) {
  959. Trap();
  960. }
  961. else {
  962. HitInt3InRtThread=0;
  963. }
  964. #endif
  965. }
  966. }
  967. #endif
  968. // Now make sure that our IRQL is never lower than DISPATCH_LEVEL.
  969. if (currentthread->irql<DISPATCH_LEVEL) {
  970. Trap();
  971. }
  972. }
  973. if (currentthread==windowsthread) {
  974. #ifdef MASKABLEINTERRUPT
  975. HandleWindowsInterrupt.offset=0;
  976. #endif
  977. // If the current thread is windows, then save CR0.
  978. // Then we can properly restore CR0 when we return to windows.
  979. LastWindowsCR0=ReadCR0();
  980. #ifdef DEBUG
  981. // Make sure that the APIC interrupt is programmed properly.
  982. if (!((*ApicPerfInterrupt)&NMI)) {
  983. #ifndef MASKABLEINTERRUPT
  984. Trap();
  985. #endif
  986. }
  987. else {
  988. #ifdef MASKABLEINTERRUPT
  989. Trap();
  990. #endif
  991. }
  992. #endif
  993. // I need to figure out how to clear pending interrupts
  994. // so that they are not generated. That is for the case
  995. // when an maskable interrupt hits after we have disabled
  996. // maskable interrupts (CLI) but before we have masked the
  997. // APIC interrupt itself.
  998. // If the ISR bit is set for our maskable interrupt then we need to
  999. // clear it.
  1000. // We only EOI the APIC if our ISR bit is set.
  1001. if (ReadAPIC(0x100+(ApicTimerVector/32)*0x10)&(1<<(ApicTimerVector%32))) {
  1002. // We have to EOI the APIC for non NMI based interrupts.
  1003. WriteAPIC(APICEOI,0);
  1004. }
  1005. #ifdef DEBUG
  1006. else {
  1007. // Our ISR bit was not set. We better have gotten here with a software interrupt.
  1008. // If we did not get here on a software interrupt instruction, then
  1009. // trap. This way of checking will work regardless of the routine
  1010. // used to transfer control. As long as an interrupt instruction is used
  1011. // to give us control.
  1012. if (*(WORD *)((*(ULONG *)(windowsthread->esp+EIPRETURNADDRESSOFFSET*sizeof(ULONG)))-2)!=(0xcd|(TRANSFERCONTROLIDTINDEX<<8))) {
  1013. Trap();
  1014. }
  1015. }
  1016. #endif
  1017. // Now in debug code make sure our ISR bit is now clear. If not, then
  1018. // we are in real trouble, because we just did an EOI if our ISR bit was
  1019. // set and that DID NOT clear our bit. It must have cleared another ISR
  1020. // bit (very bad) or the APIC is broken (also very bad).
  1021. #ifdef DEBUG
  1022. if (ReadAPIC(0x100+(ApicTimerVector/32)*0x10)&(1<<(ApicTimerVector%32))) {
  1023. Trap();
  1024. }
  1025. #endif
  1026. }
  1027. #ifdef DEBUG
  1028. // Current thread is NOT a windows thread.
  1029. // In this case the APIC interrupt should be programmed to
  1030. // be NMI, and interrupts MUST be masked. It is a FATAL
  1031. // error to unmask interrupts while inside a real time thread.
  1032. else {
  1033. if (!((*ApicPerfInterrupt)&NMI)) {
  1034. #ifndef MASKABLEINTERRUPT
  1035. Trap();
  1036. #endif
  1037. }
  1038. else {
  1039. #ifdef MASKABLEINTERRUPT
  1040. Trap();
  1041. #endif
  1042. }
  1043. // I need to decide if I got here on RtpTransferControl or not.
  1044. // If I did, then the interrupt flag I need to check is at a different
  1045. // location on the stack.
  1046. if (*(WORD *)((*(ULONG *)(currentthread->esp+EIPRETURNADDRESSOFFSET*sizeof(ULONG)))-2)!=(0xcd|(TRANSFERCONTROLIDTINDEX<<8))) {
  1047. // This was not an RtpTransferControl. It was a hardware NMI.
  1048. if (((ULONG *)(currentthread->esp))[EFLAGSOFFSET]&IF) {
  1049. // Realtime thread has interrupts ENABLED! Fatal Error!
  1050. // Everything is dead at this point. We really need to
  1051. // make it essentially impossible for real time threads
  1052. // to enable interrupts.
  1053. #ifndef MASKABLEINTERRUPT
  1054. Trap();
  1055. #endif
  1056. }
  1057. else {
  1058. #ifdef MASKABLEINTERRUPT
  1059. Trap();
  1060. #endif
  1061. }
  1062. }
  1063. else {
  1064. // We got here on an RtpTransferControl. Check the flags that got pushed
  1065. // in that routine before the CLI, so that we check the real state of the
  1066. // rt thread's interrupt flag.
  1067. if (((ULONG *)(currentthread->esp))[RTPTRANSFERCONTROLEFLAGSOFFSET]&IF) {
  1068. // Realtime thread has interrupts ENABLED! Fatal Error!
  1069. // Everything is dead at this point. We really need to
  1070. // make it essentially impossible for real time threads
  1071. // to enable interrupts.
  1072. #ifndef MASKABLEINTERRUPT
  1073. Trap();
  1074. #endif
  1075. }
  1076. else {
  1077. #ifdef MASKABLEINTERRUPT
  1078. Trap();
  1079. #endif
  1080. }
  1081. }
  1082. }
  1083. #endif
  1084. #ifdef DEBUG
  1085. // Make sure the enable floating point MMX instructions bit is set in CR4.
  1086. // If not, then the fxsave and fxrstor instructions will not work properly.
  1087. if ((CPUFeatures&FXSR) && !(ReadCR4()&OSFXSR)) {
  1088. Trap();
  1089. }
  1090. #endif
  1091. // The following code is for detecting how the IDT and CR0 are
  1092. // used by the OS.
  1093. #if defined(DEBUG) && 0
  1094. // This is monitoring code to see if anyone else in the system
  1095. // is swaping IDTs. If they are, this should catch them.
  1096. // I ran this on Win2K Pro, and did NOT hit the Trap().
  1097. // This hits constantly on 9x - just another indication that
  1098. // NT is a much better behaved environment than 9x.
  1099. // This means that we will need to SAVE the 9x IDT BEFORE we
  1100. // blast in a new value. Otherwise we will crash the OS since
  1101. // we will blow away an IDT and restore it improperly. What
  1102. // a pain.
  1103. SaveIDT(WindowsIDT);
  1104. if (WindowsIDT!=LastWindowsIDT) {
  1105. Trap();
  1106. }
  1107. LastWindowsIDT=WindowsIDT;
  1108. {
  1109. ULONG currentCR0;
  1110. currentCR0=ReadCR0();
  1111. // The MP bit should always be set.
  1112. if (!(currentCR0&FPUMONITOR)) {
  1113. Trap();
  1114. }
  1115. // The EM bit should never be set.
  1116. if (currentCR0&FPUEMULATION) {
  1117. Trap();
  1118. }
  1119. // The TS bit should never be set.
  1120. if (currentCR0&FPUTASKSWITCHED) {
  1121. Trap();
  1122. }
  1123. // The ET bit should always be set.
  1124. if (!(currentCR0&FPU387COMPATIBLE)) {
  1125. Trap();
  1126. }
  1127. // The NE bit must ALWAYS be set. This is REQUIRED, since we will run realtime threads
  1128. // with interrupts masked, so an external interrupt will NOT fire. We MUST have the
  1129. // internally generated exception.
  1130. if (!(currentCR0&FPUEXCEPTION)) {
  1131. Trap();
  1132. }
  1133. }
  1134. #endif
  1135. #ifdef DEBUG
  1136. // Make sure performance counters are not moving.
  1137. if (ReadPerformanceCounter(0)!=ReadPerformanceCounter(0)) {
  1138. Trap();
  1139. }
  1140. #endif
  1141. // The following test is broken because new PIIs update information
  1142. // in the 40-48 bit range. We need to fix this test so it works
  1143. // correctly on all processors. Intel (old and new) and AMD.
  1144. #if 0
  1145. // Make sure both performance counters are positive.
  1146. if ((ReadPerformanceCounter(0)&0x0000008000000000) ||
  1147. (ReadPerformanceCounter(1)&0x0000008000000000)) {
  1148. Trap();
  1149. }
  1150. #endif
  1151. #ifdef DEBUG
  1152. // Make sure that no APIC errors have been logged.
  1153. // Before reading the APIC status, we must write to the register
  1154. // first. That updates it with the most recent data which we then
  1155. // read. We do not need to clear the register after reading.
  1156. // The next time we write, it will latch any new status which we
  1157. // will then read.
  1158. {
  1159. ULONG ApicStatus;
  1160. WriteAPIC(APICSTATUS,0);
  1161. if (ApicStatus=ReadAPIC(APICSTATUS)) {
  1162. ApicErrorHistogram[ApicStatus&MAXAPICERRORHISTOGRAM]++;
  1163. Trap();
  1164. }
  1165. }
  1166. #endif
  1167. // See if CR0 has changed since the last interrupt.
  1168. #if 0
  1169. // If we are switching between realtime threads double check
  1170. // that the CR0 floating point state is correct. Trap if not.
  1171. if (currentthread!=windowsthread && ) {
  1172. Trap();
  1173. }
  1174. #endif
  1175. // At this point we save the floating point state if required.
  1176. if (currentthread->FloatState!=NULL) {
  1177. // If there is more than 1 thread using FLOAT or MMX, then
  1178. // we need to save the current thread's floating point state.
  1179. if (activefloatthreadcount>1) {
  1180. ULONG currentCR0;
  1181. ULONG fpubits;
  1182. currentCR0=ReadCR0();
  1183. // If CR0 has either the TS or EM bit set, then clear those
  1184. // bits in CR0 so we can save the floating point state without
  1185. // causing an exception.
  1186. // Trap if clearing the bits fails.
  1187. if (fpubits=(currentCR0&(FPUTASKSWITCHED|FPUEMULATION))) {
  1188. currentCR0^=fpubits;
  1189. WriteCR0(currentCR0);
  1190. #if DEBUG
  1191. if (currentCR0^ReadCR0()) {
  1192. Trap();
  1193. }
  1194. #endif
  1195. }
  1196. SaveThreadFloatState(currentthread->FloatState);
  1197. }
  1198. }
  1199. if (YIELD==currentthread->state) {
  1200. // Save away the mark and time for this thread.
  1201. currentthread->Mark=((PYIELDTIME)(currentthread->data))->Mark;
  1202. currentthread->Delta=((PYIELDTIME)(currentthread->data))->Delta;
  1203. }
  1204. // I need to have a complete set of statistics on all of the threads
  1205. // available to the scheduler - so it can make a good decision about what
  1206. // thread to run. That means I have to log the threadswitchtime and update
  1207. // the current thread's duration BEFORE I actually do the switch itself.
  1208. // Log threadswitch time.
  1209. lastthreadswitchtime=RtTime();
  1210. // Update just switched out thread's duration.
  1211. currentthread->Statistics->DurationRunThisPeriod+=lastthreadswitchtime-currentthread->Statistics->ThisTimesliceStartTime;
  1212. // Now we record last thread and switch to the next thread to run.
  1213. lastthread=currentthread;
  1214. if (YIELDAFTERSPINLOCKRELEASE==currentthread->state) {
  1215. if ((currentthread->data&3)!=3) {
  1216. Trap();
  1217. }
  1218. currentthread->data&=~(3);
  1219. if (YIELDAFTERSPINLOCKRELEASE==((ThreadState *)currentthread->data)->state ||
  1220. YIELD==((ThreadState *)currentthread->data)->state ||
  1221. EXIT==((ThreadState *)currentthread->data)->state ||
  1222. DEAD==((ThreadState *)currentthread->data)->state) {
  1223. Trap();
  1224. }
  1225. // Update state of currentthread to RUN.
  1226. currentthread->state=RUN;
  1227. // Just unblocked thread is now current thread to run.
  1228. currentthread=(ThreadState *)currentthread->data;
  1229. // Update the state of the just unblocked thread so that it can run.
  1230. currentthread->state=RUN;
  1231. goto nextthreadselected;
  1232. }
  1233. loopcount=0;
  1234. nextthread:
  1235. currentthread=currentthread->next;
  1236. if (loopcount++>1000) {
  1237. Trap();
  1238. }
  1239. if (currentthread!=windowsthread && (BLOCKEDONSPINLOCK==currentthread->state /*||
  1240. SPINNINGONSPINLOCK==currentthread->state*/)) {
  1241. // We allow switching back to windows even when it is blocked on a
  1242. // spinlock so that interrupts can get serviced.
  1243. // All other threads will never get switched to while they are blocked
  1244. // or spinning on a spinlock.
  1245. goto nextthread;
  1246. }
  1247. if (YIELD==currentthread->state) {
  1248. if ((lastthreadswitchtime-currentthread->Mark)>=currentthread->Delta) {
  1249. // We can run this thread. It has finished its Yield.
  1250. currentthread->state=RUN;
  1251. }
  1252. else {
  1253. // This thread is not runnable. Make sure that we are not trying
  1254. // to run it because it is holding a spinlock and is thus holding
  1255. // off some other thread. For now, just trap if that is the case.
  1256. if (lastthread!=windowsthread &&
  1257. BLOCKEDONSPINLOCK==lastthread->state &&
  1258. (ThreadState *)(lastthread->data&~(3))==currentthread) {
  1259. Trap();
  1260. }
  1261. goto nextthread;
  1262. }
  1263. }
  1264. nextthreadselected:
  1265. // Now that we have the next thread to run, increment thread switch count.
  1266. threadswitchcount++;
  1267. // Update new thread statistics.
  1268. currentthread->Statistics->TimesliceIndex++;
  1269. currentthread->Statistics->ThisTimesliceStartTime=lastthreadswitchtime;
  1270. if (currentthread->Statistics->ThisPeriodStartTime==0) {
  1271. currentthread->Statistics->ThisPeriodStartTime=lastthreadswitchtime;
  1272. }
  1273. if ((lastthreadswitchtime-currentthread->Statistics->ThisPeriodStartTime)>currentthread->Statistics->Period) {
  1274. // We have entered a new period.
  1275. // Update starttime and index.
  1276. currentthread->Statistics->ThisPeriodStartTime+=currentthread->Statistics->Period;
  1277. currentthread->Statistics->PeriodIndex++;
  1278. // Make sure we haven't dropped periods on the floor. If so, jump to current
  1279. // period.
  1280. if ((lastthreadswitchtime-currentthread->Statistics->ThisPeriodStartTime)>currentthread->Statistics->Period) {
  1281. ULONGLONG integralperiods;
  1282. integralperiods=(lastthreadswitchtime-currentthread->Statistics->ThisPeriodStartTime)/currentthread->Statistics->Period;
  1283. currentthread->Statistics->ThisPeriodStartTime+=integralperiods*currentthread->Statistics->Period;
  1284. currentthread->Statistics->PeriodIndex+=integralperiods;
  1285. }
  1286. currentthread->Statistics->TimesliceIndexThisPeriod=0;
  1287. currentthread->Statistics->DurationRunLastPeriod=currentthread->Statistics->DurationRunThisPeriod;
  1288. currentthread->Statistics->DurationRunThisPeriod=0;
  1289. }
  1290. currentthread->Statistics->TimesliceIndexThisPeriod++;
  1291. // Now restore the new threads floating point state if required.
  1292. if (currentthread->FloatState!=NULL) {
  1293. // If there is more than 1 thread using FLOAT or MMX, then
  1294. // we need to restore the current threads state.
  1295. if (activefloatthreadcount>1) {
  1296. ULONG currentCR0;
  1297. ULONG fpubits;
  1298. currentCR0=ReadCR0();
  1299. // If CR0 has either the TS or EM bit set, then clear those
  1300. // bits in CR0 so we can save the floating point state without
  1301. // causing an exception.
  1302. // Trap if clearing the bits fails.
  1303. if (fpubits=(currentCR0&(FPUTASKSWITCHED|FPUEMULATION))) {
  1304. currentCR0^=fpubits;
  1305. WriteCR0(currentCR0);
  1306. #if DEBUG
  1307. if (currentCR0^ReadCR0()) {
  1308. Trap();
  1309. }
  1310. #endif
  1311. }
  1312. RestoreThreadFloatState(currentthread->FloatState);
  1313. }
  1314. }
  1315. #if 0
  1316. if (currentthread==windowsthread && activefloatthreadcount>1) {
  1317. // Windows thread is being switched back in.
  1318. // Restore CR0. Most critical is the ts bit.
  1319. ULONG currentCR0;
  1320. currentCR0=ReadCR0();
  1321. // The TS bit should currently NEVER be set when we switch from realtime
  1322. // threads back to Windows.
  1323. if (currentCR0&FPUTASKSWITCHED) {
  1324. Trap();
  1325. }
  1326. // The EM bit should currently NEVER be set when we switch from realtime
  1327. // threads back to Windows.
  1328. if (currentCR0&FPUEMULATION) {
  1329. Trap();
  1330. }
  1331. // The NE bit must ALWAYS be set when we switch from realtime to Windows.
  1332. // NOTE: this is another CR0 bit that should be RESTORED!
  1333. if (!(currentCR0&FPUEXCEPTION)) {
  1334. Trap();
  1335. }
  1336. // Check if the TS bit state is different from its state when we left Windows.
  1337. if ((currentCR0^LastWindowsCR0)&FPUTASKSWITCHED) {
  1338. Trap();
  1339. // Switch TS back to the state it was when we took control from Windows.
  1340. currentCR0^=FPUTASKSWITCHED;
  1341. }
  1342. // See if any other bits have changed. There shouldn't be any other bits that
  1343. // change unless the debugger is mucking around.
  1344. if (currentCR0^LastWindowsCR0) {
  1345. Trap();
  1346. }
  1347. }
  1348. #endif
  1349. // Setup to load CR0.
  1350. NextCR0=ReadCR0();
  1351. // Now make sure CR0 state has correct defaults for this thread.
  1352. // If thread does not use FP or MMX, then EM=1. Otherwise EM=0.
  1353. // NE=1, ET=1, TS=0, MP=1 are other default settings.
  1354. // Set desired defaults.
  1355. NextCR0&=~(FPUMASK);
  1356. NextCR0|=FPUEXCEPTION|FPU387COMPATIBLE|FPUMONITOR;
  1357. if (currentthread->FloatState==NULL) {
  1358. // Turn on traps for FP or MMX instructions in non MMX/FP threads.
  1359. // We do this only when IDT switching is turned on since we do
  1360. // NOT want to cause traps or faults that might confuse windows.
  1361. NextCR0|=FPUEMULATION;
  1362. }
  1363. // If we current thread is windows, then make sure we restore
  1364. // CR0 to the state it had when we took control from windows.
  1365. if (currentthread==windowsthread) {
  1366. NextCR0=LastWindowsCR0;
  1367. }
  1368. NextIDT=RtThreadIDT;
  1369. if (currentthread==windowsthread) {
  1370. NextIDT=WindowsIDT;
  1371. }
  1372. #ifdef DEBUG
  1373. // Make sure that the ISR bit for our interrupt is NOT set at this point.
  1374. // It should be clear. Trap if set and force clear.
  1375. if (ReadAPIC(0x100+(ApicTimerVector/32)*0x10)&(1<<(ApicTimerVector%32))) {
  1376. Trap();
  1377. // The only way to clear this is to EOI the APIC. If our EOI does
  1378. // not clear it then we are screwed.
  1379. WriteAPIC(APICEOI, 0);
  1380. }
  1381. #endif
  1382. #ifdef MASKABLEINTERRUPT
  1383. // WARNING WARNING if you move this up to the beggining of the routine,
  1384. // do NOT forget to change lastthread to currentthread!!!!!!
  1385. if (lastthread!=windowsthread) {
  1386. // EOI the APIC for the maskable rt thread interrupt.
  1387. if (ReadAPIC(0x100+(RTMASKABLEIDTINDEX/32)*0x10)&(1<<(RTMASKABLEIDTINDEX%32))) {
  1388. WriteAPIC(APICEOI, 0);
  1389. }
  1390. else {
  1391. // Trap(); May not happen if we RtYield!!!!
  1392. }
  1393. }
  1394. // Make sure it is now clear.
  1395. if (ReadAPIC(0x100+(RTMASKABLEIDTINDEX/32)*0x10)&(1<<(RTMASKABLEIDTINDEX%32))) {
  1396. Trap();
  1397. WriteAPIC(APICEOI, 0);
  1398. }
  1399. #endif
  1400. // In debug code, make sure ALL TMR bits are clear. Trap if not.
  1401. #ifdef DEBUG
  1402. {
  1403. LONG tmr;
  1404. for (tmr=0x180;tmr<0x200;tmr+=0x10) {
  1405. if (ReadAPIC(tmr)) {
  1406. Trap();
  1407. }
  1408. }
  1409. }
  1410. #endif
  1411. // In debug code, make sure ALL ISR bits are clear. Trap if not.
  1412. #ifdef DEBUG
  1413. {
  1414. LONG isr;
  1415. for (isr=0x100;isr<0x180;isr+=0x10) {
  1416. if (ReadAPIC(isr)) {
  1417. Trap();
  1418. }
  1419. }
  1420. }
  1421. #endif
  1422. #if 0
  1423. // In debug code, make sure ALL IRR bits except ours are clear. Trap if not.
  1424. #ifdef DEBUG
  1425. {
  1426. LONG irr;
  1427. for (irr=0x200;irr<0x280;irr+=0x10) {
  1428. if (ReadAPIC(irr)) {
  1429. Trap();
  1430. }
  1431. }
  1432. }
  1433. #endif
  1434. #endif
  1435. // TODO: In debug code make sure all of our interrupts are still properly hooked.
  1436. if (lastthread->state==EXIT) {
  1437. // Remove the previous thread from the list of threads to run as
  1438. // it has exited.
  1439. // Make sure we never exit from the Windows thread.
  1440. if (lastthread==windowsthread) {
  1441. Trap();
  1442. lastthread->state=RUN; // put Windows thread back in RUN state
  1443. }
  1444. else {
  1445. // If we get here, then the lastthread has exited and is NOT the
  1446. // windows thread. So remove it from the list of running realtime
  1447. // threads.
  1448. RemoveRtThread(lastthread);
  1449. // Now atomically add it to the list of dead realtime threads - so its resources
  1450. // will be released the next time RtCreateThread or RtDestroyThread are
  1451. // called.
  1452. lastthread->next=RtDeadThreads;
  1453. while (RtpCompareExchange(&(ULONG)RtDeadThreads, (ULONG)lastthread, (ULONG)lastthread->next)!=(ULONG)lastthread) {
  1454. // If we get here, then the compare exchange failed because either another
  1455. // thread was added to the list since we read RtDeadThreads,
  1456. // or another Windows thread cleaned up the dead thread list and
  1457. // RtDeadThreads is now null when it wasn't before.
  1458. // Retry adding our thread to the list.
  1459. lastthread->next=RtDeadThreads;
  1460. }
  1461. // Mask the realtime scheduler interrupt if there is only the windows thread.
  1462. if (RtThreadCount<=1) {
  1463. // Mask the local apic timer interrupt.
  1464. *ApicTimerInterrupt=ApicTimerVector|MASKED|PERIODIC;
  1465. // Mask the performance counter interrupt.
  1466. DisablePerformanceCounterInterrupt();
  1467. }
  1468. }
  1469. }
  1470. // Make sure if there are any realtime threads that the local timer interrupt
  1471. // is enabled.
  1472. if (RtThreadCount>1) {
  1473. /*
  1474. #ifdef DEBUG
  1475. if (*ApicTimerInterrupt!=(ApicTimerVector|UNMASKED|PERIODIC)) {
  1476. Trap();
  1477. }
  1478. #endif
  1479. */
  1480. // Unmask the local apic timer interrupt.
  1481. *ApicTimerInterrupt=(ApicTimerVector|UNMASKED|PERIODIC);
  1482. }
  1483. if (currentthread==windowsthread) {
  1484. // Mask the performance counter interrupt.
  1485. DisablePerformanceCounterInterrupt();
  1486. #ifdef CATCH_INTERRUPTS_DISABLED_TOO_LONG
  1487. *ApicPerfInterrupt=ApicPerfVector|UNMASKED;
  1488. EnablePerfCounters=StopCounter;
  1489. #else
  1490. EnablePerfCounters=0;
  1491. #endif
  1492. #ifdef MASKABLEINTERRUPT
  1493. // Reset the performance counters. Perfomance HIT.
  1494. // We should NOT need to do this.
  1495. SetTimeLimit( 0, 0);
  1496. // Unmask the normal interrupts at the local apic.
  1497. *ApicIntrInterrupt=EXTINT|UNMASKED;
  1498. if (InjectWindowsInterrupt) {
  1499. HandleWindowsInterrupt.offset=InjectWindowsInterrupt;
  1500. InjectWindowsInterrupt=0;
  1501. InjectedInterruptCount++;
  1502. }
  1503. // Enable the interrupt that will get us out of windows.
  1504. // Leave the maskable performance counter interrupt masked.
  1505. // That is critical since otherwise we get invalid dyna-link
  1506. // blue screens.
  1507. WriteAPIC(APICTPR, 0x30);
  1508. #endif
  1509. }
  1510. else {
  1511. LONG timelimit;
  1512. #ifdef MASKABLEINTERRUPT
  1513. // Mask normal interrupts at the local apic.
  1514. // We do this instead of running with interrupts disabled.
  1515. // On 9x where the IO apic is not used this will work the same
  1516. // as disabling interrupts - except that now we can make the
  1517. // syncronization that depends on PUSHFD/CLI/STI/POPFD work properly.
  1518. // I can fix ntkern so it will be NMI safe, but this is the
  1519. // easiest and safest way to get the current functions safe
  1520. // it also gets us any windows functions that ntkern calls
  1521. // that depend on PUSHFD/CLI/STI/POPFD syncronization.
  1522. *ApicIntrInterrupt=EXTINT|MASKED;
  1523. // Eat APIC timer interrupts that fire during realtime threads.
  1524. // The only way that should happen is if someone in windows
  1525. // masked interrupts enough to hold off the APIC timer interrupt
  1526. // so much that the next one fired while we were still running
  1527. // our realtime threads.
  1528. *ApicTimerInterrupt=ApicTimerVector|MASKED|PERIODIC;
  1529. // Enable all of the local apic interrupts. Including the
  1530. // performance counter interrupt.
  1531. // Leave the maskable performance counter interrupt masked.
  1532. WriteAPIC(APICTPR, 0);
  1533. #endif
  1534. // Setup the performance counters for the next interrupt.
  1535. timelimit=(LONG)(RtCpuCyclesPerUsec*1000*currentthread->Statistics->Duration/currentthread->Statistics->Period);
  1536. if (timelimit<MINIMUMCYCLECOUNT) {
  1537. // In this case, we run instructions instead of cycles so that we
  1538. // can guarantee that the thread runs at least a little each slice.
  1539. timelimit=10;
  1540. EnablePerfCounters=StartInstructionCounter;
  1541. }
  1542. else {
  1543. EnablePerfCounters=StartCycleCounter;
  1544. }
  1545. SetTimeLimit(timelimit, 0);
  1546. // Unmask the performance counter interrupt.
  1547. PerformanceInterruptState&=~(MASKPERF0INT);
  1548. *ApicPerfInterrupt=ApicPerfVector|UNMASKED;
  1549. }
  1550. // Load irql for thread we are entering.
  1551. *pCurrentIrql=(KIRQL)currentthread->irql;
  1552. LoadThreadStatePointer();
  1553. RestoreSegmentState();
  1554. RestoreRegisterState();
  1555. RestoreThreadStack();
  1556. RestoreOriginalDS();
  1557. LoadCR0(NextCR0);
  1558. RestoreEAX();
  1559. LoadIDT(NextIDT);
  1560. // Fix up ds so we can access the memory we need to.
  1561. // We need a valid ds so we can save the IDT and so that we can
  1562. // check our reenter count.
  1563. __asm{
  1564. push ds
  1565. mov ds, cs:RealTimeDS
  1566. }
  1567. SaveIDT(DebugIDT);
  1568. // Paranoia: Decrement reenter count. Make sure it is zero.
  1569. // Note that until I fix the interrupt pending problem once and
  1570. // for all, I MUST decrement my reenter count BEFORE I jump to
  1571. // any injected interrupts. Since when I jump to injected interrupts,
  1572. // I WILL get reentered sometimes before the IRET occurs. That
  1573. // is OK. All that means is that Windows sat in interrupt service
  1574. // routines for the rest of the current time slice AND that Windows
  1575. // reenabled interrupts.
  1576. __asm {
  1577. dec SwitchRtThreadReenterCount
  1578. pop ds
  1579. jz leaveclean
  1580. int 3
  1581. leaveclean:
  1582. }
  1583. #ifdef MASKABLEINTERRUPT
  1584. // If we are returning to windows and we allowed interrupts when we
  1585. // left windows, and we raised irql, then we need to lower irql
  1586. // here. That will cause all of the pending dpcs to get processed.
  1587. // We are NOT guaranteed to have a flat stack, so we MUST get our
  1588. // own FLAT DS before we try to touch our variables.
  1589. __asm {
  1590. push ds
  1591. push ecx
  1592. mov ds, cs:RealTimeDS
  1593. mov ecx, currentthread
  1594. cmp ecx, windowsthread
  1595. jnz irqllowered
  1596. cmp EnabledInterrupts, 1
  1597. jl irqllowered
  1598. jz checkirql
  1599. // If we get here, then EnabledInterrupts is greater than 1. That
  1600. // should NEVER be the case. We need to crash and burn in that case.
  1601. int 3
  1602. checkirql:
  1603. int 3
  1604. dec EnabledInterrupts
  1605. mov ecx, pCurrentIrql
  1606. movzx ecx, byte ptr[ecx]
  1607. cmp ecx, OriginalIrql
  1608. je irqllowered
  1609. ja lowerirql
  1610. // We only get here, if the OriginalIrql is greater than the CurrentIrql.
  1611. // That will only happen if we screwed up.
  1612. int 3
  1613. lowerirql:
  1614. mov ecx, OriginalIrql
  1615. pushad
  1616. call WrapKfLowerIrql
  1617. popad
  1618. irqllowered:
  1619. // Restore registers.
  1620. pop ecx
  1621. pop ds
  1622. }
  1623. // Here we inject any interrupts required into windows. This code
  1624. // should almost NEVER get run.
  1625. __asm {
  1626. // Save space on stack for far return.
  1627. sub esp,8
  1628. // Get a DS we can access our data with.
  1629. push ds
  1630. mov ds, cs:RealTimeDS
  1631. // Check if we need to inject an interrupt into windows.
  1632. test HandleWindowsInterrupt.offset,0xffffffff
  1633. jz skipit
  1634. // Set up the stack with the appropriate address.
  1635. push eax
  1636. xor eax,eax
  1637. mov ax, HandleWindowsInterrupt.selector
  1638. mov dword ptr[esp+12], eax
  1639. mov eax, HandleWindowsInterrupt.offset
  1640. mov dword ptr[esp+8], eax
  1641. pop eax
  1642. // Clean up DS and jump to handler.
  1643. pop ds
  1644. retf
  1645. skipit:
  1646. // Restore DS and cleanup stack.
  1647. pop ds
  1648. add esp,8
  1649. }
  1650. #endif
  1651. TurnOnPerformanceCounters();
  1652. Return();
  1653. }
  1654. #ifdef CATCH_INTERRUPTS_DISABLED_TOO_LONG
  1655. VOID
  1656. __declspec(naked)
  1657. InterruptsHaveBeenDisabledForTooLong (
  1658. VOID
  1659. )
  1660. /*
  1661. Routine Description:
  1662. This is our replacement Windows NMI handler when we are trying to catch
  1663. code that turns off interrupts too long. If we determine that we should
  1664. not handle this interrupt, we pass it on to the original handler.
  1665. Arguments:
  1666. Return Value:
  1667. None.
  1668. */
  1669. {
  1670. __asm {
  1671. pushad
  1672. cld
  1673. mov ebp,esp
  1674. sub esp,__LOCAL_SIZE
  1675. }
  1676. // In order for this NMI to have been generated by the performance counters,
  1677. // we must have a machine that has the following state.
  1678. // 1) Supports the CPUID instruction.
  1679. // 2) Has a local APIC.
  1680. // 3) Has the local APIC enabled.
  1681. // 4) Has MSRs.
  1682. // 5) Has performance counters.
  1683. // 6) Has performance counter 1 enabled, interrupt on, counting cycles w/ints off
  1684. // 7) Performance counter 1 is greater than 0.
  1685. // If any of the above requirements are not met, this NMI was not generated by
  1686. // the performance counters and we should run the original NMI handler code.
  1687. // If all of the above requirements are met, then we check if we are in the
  1688. // debugger. If so, then we reload our count and exit. If not, then we break
  1689. // into the debugger if it is present otherwise we bugcheck.
  1690. /*
  1691. if (CpuIdOk()) {
  1692. CPUINFO cpu;
  1693. ULONG PerfControlMsr=0;
  1694. if (thecpu.==) {
  1695. }
  1696. // Make sure the machine has APIC and perf counters.
  1697. CpuId(0, &cpu);
  1698. if (cpu.eax) {
  1699. CpuId(1, &cpu);
  1700. if (cpu.edx&)
  1701. }
  1702. }
  1703. */
  1704. InterlockedIncrement(&NmiInterruptCount);
  1705. if ((ReadPerformanceCounter(1)&((PERFCOUNTMASK+1)/2))==0 &&
  1706. ReadIntelMSR(EVENTSELECT1)==StartInterruptsDisabledCounter
  1707. ) {
  1708. // We have caught someone holding off interrupts for too long.
  1709. // See if it is the debugger. If so, then reload our counter so
  1710. // that it will fire again later and drop this NMI on the floor.
  1711. // If we are not in the debugger, then we need to break in on the
  1712. // offending code so we can see who is breaking the rules and what
  1713. // they are doing.
  1714. if (*KdEnteredDebugger) {
  1715. // We are in the debugger, so simply reload the performance
  1716. // counter so it will fire again later, and eat this interrupt
  1717. // and continue.
  1718. // Setup the count.
  1719. WriteIntelMSR(PERFORMANCECOUNTER1, -MaxUsecWithInterruptsDisabled*RtCpuCyclesPerUsec);
  1720. }
  1721. else {
  1722. // We have caught a badly behaved peice of code in the middle
  1723. // of its work. Stop in the debugger so we can identify the
  1724. // code and what it is doing. Note that we do this by munging
  1725. // the stack so that when we iret we will run DbgBreakPoint with
  1726. // a stack setup so that it looks like DbgBreakPoint was called
  1727. // by the offending code, even though it wasn't. This has the
  1728. // nice side effect of clearing out the NMI.
  1729. // Note that if we want to be sneaky, we can erase our tracks
  1730. // by restoring the normal windows NMI handler so that it is
  1731. // difficult for people to figure out how they are getting caught
  1732. // and try to work around our code by patching us or turning off
  1733. // our interrupt source.
  1734. DbgPrint("Interrupts have been turned off for more than %d usec.\nBreaking in on the offending code.\n", MaxUsecWithInterruptsDisabled);
  1735. DbgBreakPoint();
  1736. // Restart the counter when we continue running.
  1737. WriteIntelMSR(PERFORMANCECOUNTER1, -MaxUsecWithInterruptsDisabled*RtCpuCyclesPerUsec);
  1738. }
  1739. }
  1740. else {
  1741. // This is NMI is coming from a source other than the performance
  1742. // counters. Send it off to the standard Windows NMI handler.
  1743. __asm {
  1744. add esp,__LOCAL_SIZE
  1745. popad
  1746. push OriginalWindowsNmiHandler
  1747. ret
  1748. }
  1749. }
  1750. __asm {
  1751. add esp,__LOCAL_SIZE
  1752. popad
  1753. }
  1754. // Now we do an IRET to return control to wherever we are going.
  1755. // Note that this clears the holdoff of further NMI's which is what we want.
  1756. // This code path gets run whenever we reload the perf counter and eat the NMI
  1757. // as well as when we break in on offending drivers.
  1758. Return();
  1759. }
  1760. VOID
  1761. ResetInterruptsDisabledCounter (
  1762. PVOID Context,
  1763. ThreadStats *Statistics
  1764. )
  1765. {
  1766. while(TRUE) {
  1767. // Reload the count.
  1768. WriteIntelMSR(PERFORMANCECOUNTER1, -MaxUsecWithInterruptsDisabled*RtCpuCyclesPerUsec);
  1769. // Start the counter counting cycles with interrupts pending and interrupts
  1770. // disabled.
  1771. WriteIntelMSR(EVENTSELECT1, StartInterruptsDisabledCounter);
  1772. RtYield(0, 0);
  1773. }
  1774. }
  1775. VOID
  1776. SetupInterruptsDisabledPerformanceCounter (
  1777. VOID
  1778. )
  1779. {
  1780. // Event counter one counts cycles with interrupts disabled and interrupts
  1781. // pending. We set this counter up so that it overflows when interrupts
  1782. // have been disabled with interrupts pending for more than
  1783. // InterruptsDisabledLimit microseconds.
  1784. // Disable the counter while we are setting it up.
  1785. WriteIntelMSR(EVENTSELECT1, STOPPERFCOUNTERS);
  1786. // Setup the count.
  1787. WriteIntelMSR(PERFORMANCECOUNTER1, -MaxUsecWithInterruptsDisabled*RtCpuCyclesPerUsec);
  1788. // Now unmask performance counter interrupt.
  1789. *ApicPerfInterrupt=ApicPerfVector|UNMASKED;
  1790. // Start the counter counting cycles with interrupts pending and interrupts
  1791. // disabled.
  1792. WriteIntelMSR(EVENTSELECT1, StartInterruptsDisabledCounter);
  1793. }
  1794. #endif
  1795. HANDLE
  1796. RtpCreateUniqueThreadHandle (
  1797. VOID
  1798. )
  1799. {
  1800. ULONG newhandle,lasthandle;
  1801. newhandle=RtLastUniqueThreadHandle;
  1802. while ((newhandle+1)!=(lasthandle=RtpCompareExchange(&RtLastUniqueThreadHandle,newhandle+1,newhandle))) {
  1803. newhandle=lasthandle;
  1804. }
  1805. return (HANDLE)(newhandle+1);
  1806. }
  1807. NTSTATUS
  1808. RtpInitializeThreadList (
  1809. VOID
  1810. )
  1811. {
  1812. ThreadState *initialthread;
  1813. ASSERT( currentthread == NULL && windowsthread == NULL );
  1814. // Allocate a thread block for Windows.
  1815. initialthread=(ThreadState *)ExAllocatePool( NonPagedPool, sizeof(ThreadState) );
  1816. if (initialthread==NULL) {
  1817. return STATUS_NO_MEMORY;
  1818. }
  1819. // There is no StackBase for Windows.
  1820. initialthread->StackBase=NULL;
  1821. // Allocate a statistics block for Windows.
  1822. initialthread->Statistics=(ThreadStats *)ExAllocatePool( NonPagedPool, sizeof(ThreadStats) );
  1823. if (initialthread->Statistics==NULL) {
  1824. ExFreePool(initialthread);
  1825. return STATUS_NO_MEMORY;
  1826. }
  1827. // Initialize the statistics block.
  1828. RtlZeroMemory(initialthread->Statistics, sizeof(ThreadStats));
  1829. initialthread->Statistics->Period=MSEC;
  1830. initialthread->Statistics->Duration=(MSEC*133)/RtCpuCyclesPerUsec;
  1831. initialthread->Statistics->Flags=USESFLOAT|USESMMX;
  1832. // Allocate space for floating point state for Windows.
  1833. initialthread->FloatBase=ExAllocatePool( NonPagedPool, FLOATSTATESIZE+FXALIGN );
  1834. if (initialthread->FloatBase==NULL) {
  1835. ExFreePool(initialthread->Statistics);
  1836. ExFreePool(initialthread);
  1837. return STATUS_NO_MEMORY;
  1838. }
  1839. RtlZeroMemory(initialthread->FloatBase, FLOATSTATESIZE+FXALIGN);
  1840. // Now 16 byte align the floating point state pointer so fxsave/fxrstor can
  1841. // be used if supported.
  1842. initialthread->FloatState=(PVOID)(((ULONG)initialthread->FloatBase+(FXALIGN-1))&~(FXALIGN-1));
  1843. // Get a handle for the windows thread.
  1844. initialthread->ThreadHandle=RtpCreateUniqueThreadHandle();
  1845. // Set initial state and data for the windows thread.
  1846. initialthread->state=RUN;
  1847. initialthread->data=0;
  1848. // Setup windows thread state.
  1849. initialthread->next=initialthread;
  1850. initialthread->previous=initialthread;
  1851. // Initialize list spinlock.
  1852. KeInitializeSpinLock(&RtThreadListSpinLock);
  1853. // Count it as a float thread.
  1854. activefloatthreadcount++;
  1855. // Update our RT thread count.
  1856. RtThreadCount++;
  1857. // Allocate Windows thread its CPU. For now we give it at least 133MHz.
  1858. RtCpuAllocatedPerMsec=(ULONG)(initialthread->Statistics->Duration);
  1859. // Add it to the list.
  1860. windowsthread=currentthread=initialthread;
  1861. return STATUS_SUCCESS;
  1862. }
  1863. VOID
  1864. HookWindowsInterrupts (
  1865. ULONG TimerVector,
  1866. ULONG ErrorVector
  1867. )
  1868. {
  1869. // Hook the NMI interrupt vector.
  1870. //HookInterrupt(NMIIDTINDEX, &OriginalNmiVector, SwitchRealTimeThreads);
  1871. #ifdef CATCH_INTERRUPTS_DISABLED_TOO_LONG
  1872. HookInterrupt(NMIIDTINDEX, &OriginalNmiVector, InterruptsHaveBeenDisabledForTooLong);
  1873. OriginalWindowsNmiHandler=OriginalNmiVector.lowoffset | OriginalNmiVector.highoffset<<16;
  1874. #endif
  1875. // Hook the maskable interrupt vector as well.
  1876. HookInterrupt(TimerVector, &OriginalMaskableVector, SwitchRealTimeThreads);
  1877. // Hook the APIC error interrupt vector.
  1878. // Note that we only do this if both of the local APIC vectors match the
  1879. // defaults, since otherwise the HAL will have already loaded a vector
  1880. // for handling APIC errors - and we don't want to hook theirs out.
  1881. if (TimerVector==MASKABLEIDTINDEX && ErrorVector==APICERRORIDTINDEX) {
  1882. // HAL has not programmed the IDT already. (Yes, the hal could
  1883. // potentially use the same vectors we do, but none of the existing
  1884. // hals do.)
  1885. HookInterrupt(ErrorVector, &OriginalApicErrorVector, RtpLocalApicErrorHandler);
  1886. }
  1887. }
  1888. VOID
  1889. SetupPerformanceCounters (
  1890. VOID
  1891. )
  1892. {
  1893. // Initialize the performance counters.
  1894. // Event counter zero counts cycles. Interrupt disabled.
  1895. // Counters disabled.
  1896. WriteIntelMSR(EVENTSELECT0, STOPPERFCOUNTERS);
  1897. // Zero the counts.
  1898. WriteIntelMSR(PERFORMANCECOUNTER0, 0);
  1899. if (CPUManufacturer==INTEL && CPUFamily==0xf) {
  1900. // Setup escr register in Willamette processor.
  1901. WriteIntelMSR(WILLAMETTEESCR0, 0x05fffe0c);
  1902. }
  1903. // Now setup performance counter interrupt.
  1904. *ApicPerfInterrupt=ApicPerfVector|MASKED;
  1905. }
  1906. #ifndef UNDER_NT
  1907. #pragma warning ( disable : 4035 )
  1908. ULONGLONG
  1909. __declspec(naked)
  1910. _cdecl
  1911. AllocateGDTSelector (
  1912. ULONG HiDWORD,
  1913. ULONG LowDWORD,
  1914. ULONG flags
  1915. )
  1916. {
  1917. VxDJmp( _Allocate_GDT_Selector );
  1918. }
  1919. ULONG
  1920. __declspec(naked)
  1921. _cdecl
  1922. FreeGDTSelector (
  1923. ULONG Selector,
  1924. ULONG flags
  1925. )
  1926. {
  1927. VxDJmp( _Free_GDT_Selector );
  1928. }
  1929. #pragma warning ( default : 4035 )
  1930. #endif
  1931. NTSTATUS
  1932. InitializeRealTimeStack (
  1933. VOID
  1934. )
  1935. {
  1936. ULONGLONG gdtselector;
  1937. // Allocate and initialize a new code segment descriptor in
  1938. // the GDT.
  1939. #ifdef UNDER_NT
  1940. gdtselector=0x8;
  1941. #else
  1942. gdtselector=AllocateGDTSelector(0x00cf9b00, 0x0000ffff, 0);
  1943. #endif
  1944. RtExecCS=(WORD)gdtselector;
  1945. #ifdef USERING1
  1946. // Allocate and initialize a ring 1 code segment descriptor in
  1947. // the GDT for our real time threads.
  1948. #ifdef UNDER_NT
  1949. gdtselector=0x8;
  1950. #else
  1951. gdtselector=AllocateGDTSelector(0x00cfbb00, 0x0000ffff, 0);
  1952. #endif
  1953. RtThreadCS=(WORD)gdtselector;
  1954. #else
  1955. RtThreadCS=RtExecCS;
  1956. #endif
  1957. // Allocate and initialize a new data segment descriptor in
  1958. // the GDT.
  1959. #ifdef UNDER_NT
  1960. gdtselector=0x10;
  1961. #else
  1962. //gdtselector=AllocateGDTSelector(0x00cf9300,0x0000ffff, 0);
  1963. // To catch null pointer accesses in realtime threads, we make this selector
  1964. // expand down and put the bottom 64k of memory off limits.
  1965. gdtselector=AllocateGDTSelector(0x00c09700,0x0000000f, 0);
  1966. #endif
  1967. RealTimeDS=(WORD)gdtselector;
  1968. RealTimeSS=(WORD)gdtselector;
  1969. #ifdef GUARD_PAGE
  1970. // Now allocate a TSS for our realtime thread double fault handler.
  1971. {
  1972. ULONG highdword;
  1973. ULONG lowdword;
  1974. lowdword=(ULONG)&RtTss;
  1975. highdword=lowdword&0xffff0000;
  1976. lowdword<<=16;
  1977. lowdword|=sizeof(RtTss)-1;
  1978. highdword|=highdword>>16;
  1979. highdword&=0xff0000ff;
  1980. highdword|=0x00108900;
  1981. gdtselector=AllocateGDTSelector(highdword, lowdword, PAGEFRMINST);
  1982. RtExecTSS=(WORD)gdtselector;
  1983. }
  1984. // Allocate and initialize a read only Ring 3data segment descriptor
  1985. // in the GDT that our ring 3 code can use to look at our
  1986. // data structures.
  1987. gdtselector=AllocateGDTSelector(0x00cff100,0x0000ffff, 0);
  1988. RtRing3Selector=(WORD)gdtselector;
  1989. #endif
  1990. // Point our stack segment at it.
  1991. RealTimeStack.ss=RealTimeSS;
  1992. // Point our stack pointer at the top of our local stack.
  1993. RealTimeStack.esp=(ULONG)(LocalStack+LOCALSTACKSIZE-1);
  1994. if (!RtExecCS || !RtThreadCS || !RealTimeDS || !RealTimeSS) {
  1995. return STATUS_UNSUCCESSFUL;
  1996. }
  1997. return STATUS_SUCCESS;
  1998. }
  1999. NTSTATUS
  2000. RtpCalibrateCpuClock (
  2001. ULONG *cyclesperusec
  2002. )
  2003. {
  2004. ULONG i;
  2005. ULONG cycles;
  2006. ULONG *histogram;
  2007. #define MAXCYCLESPERTICK 16384
  2008. #define CPUCALIBRATECOUNT 1024
  2009. // This is the number of times we will measure the CPU clock speed.
  2010. // Each measurement takes ~24us so measuring it 1024 times will take
  2011. // about 25ms.
  2012. // To do this calibration, we measure the CPU clock speed quickly
  2013. // many many times, and then we look at the distribution and choose
  2014. // the most frequently measured value as the correct CPU speed.
  2015. if (RtRunning) {
  2016. Trap();
  2017. return STATUS_UNSUCCESSFUL;
  2018. }
  2019. histogram=ExAllocatePool(NonPagedPool, MAXCYCLESPERTICK*sizeof(ULONG));
  2020. if (histogram==NULL) {
  2021. return STATUS_NO_MEMORY;
  2022. }
  2023. RtlZeroMemory(histogram, MAXCYCLESPERTICK*sizeof(ULONG));
  2024. // First we collect the measurements.
  2025. for (i=0; i<CPUCALIBRATECOUNT; i++) {
  2026. // Make the measurement. Note that interrupts must be disabled.
  2027. SaveAndDisableMaskableInterrupts();
  2028. cycles=MeasureCPUCyclesPerTick();
  2029. RestoreMaskableInterrupts();
  2030. // Make sure we stay within our measurement limits. So we don't
  2031. // trash memory.
  2032. if (cycles>=MAXCYCLESPERTICK) {
  2033. cycles=MAXCYCLESPERTICK-1;
  2034. }
  2035. histogram[cycles]++;
  2036. }
  2037. // Stop if we have hit the limits of our histogram. This will happen when
  2038. // someone ships a processor that runs faster than MAXCYCLESPERTICK-1 MHz.
  2039. if (histogram[MAXCYCLESPERTICK-1]) {
  2040. dprintf(("This CPU runs faster than %d MHz. Update MAXCYCLESPERTICK!", MAXCYCLESPERTICK-1));
  2041. Break();
  2042. }
  2043. // Now process the measurements and choose the optimal CPU speed.
  2044. {
  2045. ULONG totalcount;
  2046. cycles=1;
  2047. totalcount=0;
  2048. // Scan through all of the possible measurement values looking for
  2049. // the most frequently reported one.
  2050. // We ignore measurements of zero, since they indicate some sort of error
  2051. // occured in MeasureCPUCyclesPerTick.
  2052. // Count any measurements that failed, so we properly quit the scan as soon
  2053. // as we have considered all the measurements we took.
  2054. totalcount+=histogram[0];
  2055. for (i=1; i<MAXCYCLESPERTICK; i++) {
  2056. if (histogram[i]>histogram[cycles]) {
  2057. cycles=i;
  2058. }
  2059. totalcount+=histogram[i];
  2060. // Quit if we have already scanned all the measurements.
  2061. if (totalcount>=CPUCALIBRATECOUNT) {
  2062. break;
  2063. }
  2064. }
  2065. }
  2066. ExFreePool(histogram);
  2067. *cyclesperusec=(ULONG)(((ULONGLONG)cycles*1193182+(1000000/2))/1000000);
  2068. dprintf(("RealTime Executive measured a CPU clock speed of %d MHz.", *cyclesperusec));
  2069. return STATUS_SUCCESS;
  2070. }
  2071. NTSTATUS
  2072. RtpMeasureSystemBusSpeed (
  2073. ULONG CpuCyclesPerUsec,
  2074. ULONG *SystemBusCyclesPerUsec
  2075. )
  2076. {
  2077. ULONGLONG starttime, finaltime;
  2078. ULONG finalcount;
  2079. ULONG OriginalTimerInterruptControl;
  2080. ULONG OriginalTimerInitialCount;
  2081. ULONG OriginalTimerDivide;
  2082. #define STARTCOUNT 0xffffffff
  2083. // Save the local APIC timer state.
  2084. OriginalTimerDivide=ReadAPIC(APICTIMERDIVIDE);
  2085. OriginalTimerInterruptControl=ReadAPIC(APICTIMER);
  2086. OriginalTimerInitialCount=ReadAPIC(APICTIMERINITIALCOUNT);
  2087. // Make sure the timer interrupt is masked and is setup as a
  2088. // one shot counter. Note that we are masking the interrupt, so we may
  2089. // caused dropped interrupts while doing this calibration if there
  2090. // is other code in the system using the local APIC timer.
  2091. // If there is not a valid interrupt vector in the timer, then put one
  2092. // there. Otherwise the local apic logs a received an illegal vector
  2093. // error and with debug bits we trap in switchrealtimethreads.
  2094. if ( (OriginalTimerInterruptControl&VECTORMASK)==0 ) {
  2095. OriginalTimerInterruptControl|=ApicTimerVector;
  2096. }
  2097. WriteAPIC(APICTIMER, (OriginalTimerInterruptControl&VECTORMASK)|MASKED|ONESHOT);
  2098. // Now calibrate the timer. We use the already calibrated CPU speed
  2099. // to calibrate the timer.
  2100. // We calibrate the timer by setting it to count down from its max,
  2101. // delaying 10us, and then calculating the number of counts per usec.
  2102. // First make sure the timer is zeroed. If not zero it. That will
  2103. // stop it counting.
  2104. if (OriginalTimerInitialCount) {
  2105. // On Win9x the OriginalTimerInitialCount should always be zero.
  2106. // On NT, it won't be for hals that use the local APIC.
  2107. #ifndef UNDER_NT
  2108. Trap();
  2109. #endif
  2110. WriteAPIC(APICTIMERINITIALCOUNT, 0);
  2111. }
  2112. // Make sure counter is stopped. If not, then punt.
  2113. if (ReadAPIC(APICTIMERINITIALCOUNT) ||
  2114. ReadAPIC(APICTIMERCURRENTCOUNT)) {
  2115. Trap();
  2116. return STATUS_UNSUCCESSFUL;
  2117. }
  2118. // Setup the timer to count single bus cycles.
  2119. WriteAPIC(APICTIMERDIVIDE, DIVIDEBY1);
  2120. // Set the timer to its maximum possible count. This will start
  2121. // the timer counting.
  2122. SaveAndDisableMaskableInterrupts();
  2123. finaltime=starttime=ReadCycleCounter();
  2124. WriteAPIC(APICTIMERINITIALCOUNT, STARTCOUNT);
  2125. while ((ULONG)(finaltime-starttime)<10*RtCpuCyclesPerUsec) {
  2126. finaltime=ReadCycleCounter();
  2127. }
  2128. finalcount=ReadAPIC(APICTIMERCURRENTCOUNT);
  2129. RestoreMaskableInterrupts();
  2130. // Stop the local apic timer.
  2131. WriteAPIC(APICTIMERINITIALCOUNT, 0);
  2132. // Restore local apic timer settings.
  2133. WriteAPIC(APICTIMERDIVIDE, OriginalTimerDivide);
  2134. WriteAPIC(APICTIMER, OriginalTimerInterruptControl);
  2135. WriteAPIC(APICTIMERINITIALCOUNT, OriginalTimerInitialCount);
  2136. // Calculate and return the bus speed of this system.
  2137. *SystemBusCyclesPerUsec=(((STARTCOUNT-finalcount)*CpuCyclesPerUsec)+((ULONG)(finaltime-starttime)/2))/(ULONG)(finaltime-starttime);
  2138. return STATUS_SUCCESS;
  2139. }
  2140. NTSTATUS
  2141. RtpCalibrateSystemBus (
  2142. ULONG CpuCyclesPerUsec,
  2143. ULONG *SystemBusCyclesPerUsec
  2144. )
  2145. {
  2146. ULONG i;
  2147. ULONG cycles;
  2148. ULONG *histogram;
  2149. #define MAXSYSTEMCLOCKSPEED 4096
  2150. #define SYSTEMBUSCALIBRATECOUNT 512
  2151. // This is the number of times we will measure the system bus speed.
  2152. // Each measurement takes ~10us so measuring it 512 times will take
  2153. // about 5ms.
  2154. // To do this calibration, we measure the CPU clock speed quickly
  2155. // many many times, and then we look at the distribution and choose
  2156. // the most frequently measured value as the correct CPU speed.
  2157. if (RtRunning) {
  2158. Trap();
  2159. return STATUS_UNSUCCESSFUL;
  2160. }
  2161. histogram=ExAllocatePool(NonPagedPool, MAXSYSTEMCLOCKSPEED*sizeof(ULONG));
  2162. if (histogram==NULL) {
  2163. return STATUS_NO_MEMORY;
  2164. }
  2165. RtlZeroMemory(histogram, MAXSYSTEMCLOCKSPEED*sizeof(ULONG));
  2166. // First we collect the measurements.
  2167. for (i=0; i<SYSTEMBUSCALIBRATECOUNT; i++) {
  2168. cycles=0;
  2169. RtpMeasureSystemBusSpeed(CpuCyclesPerUsec, &cycles);
  2170. // Make sure we stay within our measurement limits. So we don't
  2171. // trash memory.
  2172. if (cycles>=MAXSYSTEMCLOCKSPEED) {
  2173. cycles=MAXSYSTEMCLOCKSPEED-1;
  2174. }
  2175. histogram[cycles]++;
  2176. }
  2177. // Stop if we have hit the limits of our histogram. This will happen when
  2178. // someone ships a machine with a system bus that runs faster than MAXSYSTEMCLOCKSPEED-1 MHz.
  2179. if (histogram[MAXSYSTEMCLOCKSPEED-1]) {
  2180. dprintf(("This system bus runs faster than %d MHz. Update MAXSYSTEMCLOCKSPEED!", MAXSYSTEMCLOCKSPEED-1));
  2181. Break();
  2182. }
  2183. // Now process the measurements and choose the optimal system bus speed.
  2184. {
  2185. ULONG totalcount;
  2186. cycles=1;
  2187. totalcount=0;
  2188. // Scan through all of the possible measurement values looking for
  2189. // the most frequently reported one.
  2190. // We ignore measurements of zero, since they indicate some sort of error
  2191. // occured in RtpMeasureSystemBusSpeed.
  2192. // Count any measurements that failed, so we properly quit the scan as soon
  2193. // as we have considered all the measurements we took.
  2194. totalcount+=histogram[0];
  2195. for (i=1; i<MAXSYSTEMCLOCKSPEED; i++) {
  2196. if (histogram[i]>histogram[cycles]) {
  2197. cycles=i;
  2198. }
  2199. totalcount+=histogram[i];
  2200. // Quit if we have already scanned all the measurements.
  2201. if (totalcount>=SYSTEMBUSCALIBRATECOUNT) {
  2202. break;
  2203. }
  2204. }
  2205. }
  2206. ExFreePool(histogram);
  2207. *SystemBusCyclesPerUsec=cycles;
  2208. dprintf(("RealTime Executive measured a system bus speed of %d MHz.", *SystemBusCyclesPerUsec));
  2209. return STATUS_SUCCESS;
  2210. }
  2211. // This function sets up and turns on the local APIC timer. It
  2212. // programs it to generate an interrupt once per MS. This is the
  2213. // interrupt that we will use to take control from Windows. This
  2214. // is a maskable interrupt.
  2215. NTSTATUS
  2216. RtpEnableApicTimer (
  2217. VOID
  2218. )
  2219. {
  2220. // Stop the timer.
  2221. WriteAPIC(APICTIMERINITIALCOUNT, 0);
  2222. // Make sure counter is stopped. If not, then punt.
  2223. if (ReadAPIC(APICTIMERINITIALCOUNT) ||
  2224. ReadAPIC(APICTIMERCURRENTCOUNT)) {
  2225. Trap();
  2226. return STATUS_UNSUCCESSFUL;
  2227. }
  2228. // Make the timer interrupt a periodic interrupt. Leave it masked
  2229. // for now.
  2230. WriteAPIC(APICTIMER, ApicTimerVector|MASKED|PERIODIC);
  2231. // Setup the timer to count single cycles.
  2232. WriteAPIC(APICTIMERDIVIDE, DIVIDEBY1);
  2233. // Start the timer up. It should fire every MS.
  2234. // This is our failsafe for getting control to Windows on aggressively
  2235. // power managed machines that turn off the CPU at every chance they
  2236. // get. Unfortunately, I don't yet know of a performance counter that
  2237. // will count bus cycles or some other entity that doesn't stop when
  2238. // the processor is stopped.
  2239. WriteAPIC(APICTIMERINITIALCOUNT, 1000*RtSystemBusCyclesPerUsec);
  2240. return STATUS_SUCCESS;
  2241. }
  2242. VOID
  2243. RtpSetupStreamingSIMD (
  2244. VOID
  2245. )
  2246. {
  2247. // If the CPU supports floating point MMX instructions, then make sure CR4
  2248. // is setup so that fxsave and fxrstor instructions will work properly.
  2249. // The OS should have already set this bit to the proper state. If not,
  2250. // then we trap in both retail and debug, since our setting this bit
  2251. // may cause problems.
  2252. if (CPUFeatures&FXSR) {
  2253. ULONG reg;
  2254. SaveAndDisableMaskableInterrupts();
  2255. reg=ReadCR4();
  2256. if (!(reg&OSFXSR)) {
  2257. // Trap in retail and debug.
  2258. Break();
  2259. // Force the bit set.
  2260. WriteCR4(reg|OSFXSR);
  2261. }
  2262. RestoreMaskableInterrupts();
  2263. }
  2264. }
  2265. VOID
  2266. TurnOffLocalApic (
  2267. VOID
  2268. )
  2269. {
  2270. SaveAndDisableMaskableInterrupts();
  2271. // First mask and clear all of the local interrupt sources.
  2272. WriteAPIC(APICPERF, MASKED);
  2273. WriteAPIC(APICERROR, MASKED);
  2274. WriteAPIC(APICTIMER, MASKED);
  2275. WriteAPIC(APICNMI, MASKED);
  2276. WriteAPIC(APICINTR, MASKED);
  2277. // Now stop the local apic timer.
  2278. WriteAPIC(APICTIMERINITIALCOUNT, 0);
  2279. // Now disable the local apic.
  2280. WriteAPIC(APICSPURIOUS,0x100);
  2281. // Now turn it off with the MSRs.
  2282. WriteIntelMSR(APICBASE, ReadIntelMSR(APICBASE)&(~0x800I64));
  2283. RestoreMaskableInterrupts();
  2284. }
  2285. // This function is called when we are going down into hibernate and
  2286. // we hit the interrupts disabled phase. We should be the last driver
  2287. // to get called in this situation. We clear all of the APIC settings
  2288. // and then turn the APIC off.
  2289. NTSTATUS
  2290. ShutdownAPIC (
  2291. VOID
  2292. )
  2293. {
  2294. // We only ever need to do this if we were running before.
  2295. if (!RtRunning) {
  2296. return STATUS_NOT_SUPPORTED;
  2297. }
  2298. TurnOffLocalApic();
  2299. // Now read the timestamp counter shutdown count. We use this to properly
  2300. // restore the time when we wake up - if needed. (Will be needed for
  2301. // hibernate cases, will also be needed on ACPI machines that take power
  2302. // from CPU in S2 and S3.)
  2303. RtShutdownTime=RtTime();
  2304. return STATUS_SUCCESS;
  2305. }
  2306. NTSTATUS
  2307. RestartAPIC (
  2308. VOID
  2309. )
  2310. {
  2311. CPUINFO cpuinfo;
  2312. // First we decide if we need to reprogram the APIC.
  2313. // We do this by first reading the CPU features with the cpu ID instruction.
  2314. // Then we check if the APIC bit is set. If so, then everything should
  2315. // be OK. In the debug code we validate a bunch of stuff to make sure.
  2316. // If the APIC bit is NOT set in the features bit, then we know we need
  2317. // to turn the APIC back on. So we do.
  2318. // We only ever need to do this if we were running before.
  2319. if (!RtRunning) {
  2320. return STATUS_NOT_SUPPORTED;
  2321. }
  2322. // Get the cpu features.
  2323. if (!GetCpuId(1,&cpuinfo)) {
  2324. return STATUS_UNSUCCESSFUL;
  2325. }
  2326. // If the APIC is already on, then do nothing.
  2327. if (cpuinfo.edx&APIC) {
  2328. return STATUS_UNSUCCESSFUL;
  2329. }
  2330. // Prevent Trap() in RtTime. Fixup thread Statistic timestamps.
  2331. if ((LONGLONG)((ULONGLONG)ReadCycleCounter()-lasttime)<0) {
  2332. ULONGLONG RtStartupTime;
  2333. ThreadState *thread;
  2334. //KIRQL OldIrql;
  2335. lasttime=0;
  2336. RtStartupTime=RtTime();
  2337. // Fix ThisTimesliceStartTime for the windows thread.
  2338. windowsthread->Statistics->ThisTimesliceStartTime-=RtShutdownTime;
  2339. windowsthread->Statistics->ThisTimesliceStartTime+=RtStartupTime;
  2340. // Also fix up ThisPeriodStartTime for each and every rt thread.
  2341. //KeAcquireSpinLock(&RtThreadListSpinLock,&OldIrql);
  2342. thread=windowsthread;
  2343. do {
  2344. thread->Statistics->ThisPeriodStartTime-=RtShutdownTime;
  2345. thread->Statistics->ThisPeriodStartTime+=RtStartupTime;
  2346. thread=thread->next;
  2347. } while(thread!=windowsthread);
  2348. //KeReleaseSpinLock(&RtThreadListSpinLock, OldIrql);
  2349. }
  2350. if (!EnableAPIC()) {
  2351. return STATUS_UNSUCCESSFUL;
  2352. }
  2353. if ( !NT_SUCCESS(RtpEnableApicTimer()) ) {
  2354. return STATUS_UNSUCCESSFUL;
  2355. }
  2356. RtpSetupStreamingSIMD();
  2357. SetupPerformanceCounters();
  2358. SetTimeLimit( 0, 0);
  2359. if (RtThreadCount>1) {
  2360. WriteAPIC(APICTIMER, ApicTimerVector|UNMASKED|PERIODIC);
  2361. }
  2362. return STATUS_SUCCESS;
  2363. }
  2364. // Ideas:
  2365. // We should maintain a thread state and data associated with that state
  2366. // for all threads.
  2367. // We set the state/data and then transfer control to the executive.
  2368. // The default state of a thread is RUNNING.
  2369. // Other possible states, DEAD, YIELDEDTIMESLICE, YIELDEDPERIOD,
  2370. // RELEASEDSPINLOCK (data=thread handle to yield to)
  2371. // We can add states as we please and define the new mappings between
  2372. // those states.
  2373. // For now my states are RUNNING, YIELDEDTIMESLICE, YIELDEDPERIOD, DEAD
  2374. #ifndef UNDER_NT
  2375. /*
  2376. PowerFunc
  2377. Power function. Can be one of these values:
  2378. #define PF_SUSPEND_PHASE1 0x00000000
  2379. #define PF_SUSPEND_PHASE2 0x00000001
  2380. #define PF_SUSPEND_INTS_OFF 0x00000002
  2381. #define PF_RESUME_INTS_OFF 0x00000003
  2382. #define PF_RESUME_PHASE2 0x00000004
  2383. #define PF_RESUME_PHASE1 0x00000005
  2384. #define PF_BATTERY_LOW 0x00000006
  2385. #define PF_POWER_STATUS_CHANGE 0x00000007
  2386. #define PF_UPDATE_TIME 0x00000008
  2387. #define PF_CAPABILITIES_CHANGE 0x00000009
  2388. #define PF_USER_ARRIVED 0x0000000A
  2389. #define PF_PRE_FLUSH_DISKS 0x0000000B
  2390. #define PF_APMOEMEVENT_FIRST 0x00000200
  2391. #define PF_APMOEMEVENT_LAST 0x000002FF
  2392. Flags
  2393. #define PFG_UI_ALLOWED 0x00000001
  2394. #define PFG_CANNOT_FAIL 0x00000002
  2395. #define PFG_REQUEST_VETOED 0x00000004
  2396. #define PFG_REVERSE 0x00000008
  2397. #define PFG_STANDBY 0x00000010
  2398. #define PFG_CRITICAL 0x00000020
  2399. #define PFG_RESUME_AUTOMATIC 0x00000040
  2400. #define PFG_USER_ARRIVED 0x00000080
  2401. #define PFG_HIBERNATE 0x00000100
  2402. #define PFG_FAKE_RESUME 0x00000200
  2403. Power flags. Can be one of these values: PFG_UI_ALLOWED (0x00000001)
  2404. PFG_CANNOT_FAIL (0X00000002)
  2405. PFG_REQUEST_VETOED (0X00000004) Indicates that the user may not be available
  2406. to answer questions prior to the suspend operation. If this value is not given
  2407. , higher levels of software may attempt some user interaction prior to
  2408. accepting a suspend request.
  2409. PFG_REVERSE (0x00000008) Clear for suspend operations, set on resume.
  2410. PFG_STANDBY (0x00000010) Indicates a standby request when set as opposed to
  2411. a suspend request.
  2412. PFG_CRITICAL (0x00000020) Set to notify power handlers of critical resume
  2413. operations so that they may attempt to resume their clients as best as
  2414. possible. Critical suspends do not reach the power handlers in order to
  2415. maintain compliance with the APM 1.1 specification.
  2416. //
  2417. // Standard POWER_HANDLER priority levels.
  2418. //
  2419. #define PHPL_PBT_BROADCAST 0x40000000
  2420. #define PHPL_NTKERN 0x60000000
  2421. #define PHPL_UNKNOWN 0x80000000
  2422. #define PHPL_CONFIGMG 0xC0000000
  2423. #define PHPL_PCI 0xC8000000 // Must be after CONFIGMG
  2424. #define PHPL_ACPI 0xD0000000 // Must be after CONFIGMG
  2425. #define PHPL_IOS 0xD8000000 // Must be after ACPI
  2426. #define PHPL_PIC 0xE0000000
  2427. #define PHPL_TIMER 0xF0000000 // Must be after PIC
  2428. //
  2429. // If you want the ints off phase, you must have the A5 in the low byte
  2430. // of the priority level.
  2431. //
  2432. #define PHPL_HANDLE_INTS_OFF 0x000000A5
  2433. */
  2434. ULONG ApicRestartCount=0;
  2435. POWERRET _cdecl RtpPowerHandler(POWERFUNC PowerFunc, ULONG Flags)
  2436. {
  2437. switch(PowerFunc) {
  2438. case PF_SUSPEND_PHASE1:
  2439. break;
  2440. case PF_SUSPEND_PHASE2:
  2441. break;
  2442. case PF_SUSPEND_INTS_OFF:
  2443. // We are going down into hibernate or suspend. Shutdown the local APIC.
  2444. // I HAVE to do this because on some machines we will go down into S3 on
  2445. // suspend, and that will blow away the local apic state - since the processor
  2446. // can be powered down when we are in S3. Actually processor may lose power
  2447. // even in S2.
  2448. ShutdownAPIC();
  2449. break;
  2450. case PF_RESUME_INTS_OFF:
  2451. if (!(Flags&PFG_FAKE_RESUME)) {
  2452. // We are coming up out of hibernate or suspend. Turn the local APIC back on.
  2453. // Make sure we don't do it for the fake resume. Only for the real resume.
  2454. if (RestartAPIC()==STATUS_SUCCESS)
  2455. ApicRestartCount++;
  2456. }
  2457. break;
  2458. case PF_RESUME_PHASE2:
  2459. break;
  2460. case PF_RESUME_PHASE1:
  2461. break;
  2462. case PF_BATTERY_LOW:
  2463. break;
  2464. case PF_POWER_STATUS_CHANGE:
  2465. break;
  2466. case PF_UPDATE_TIME:
  2467. break;
  2468. case PF_CAPABILITIES_CHANGE:
  2469. break;
  2470. case PF_USER_ARRIVED:
  2471. break;
  2472. case PF_PRE_FLUSH_DISKS:
  2473. break;
  2474. case PF_APMOEMEVENT_FIRST:
  2475. break;
  2476. case PF_APMOEMEVENT_LAST:
  2477. break;
  2478. default:
  2479. Trap();
  2480. break;
  2481. }
  2482. return PR_SUCCESS;
  2483. }
  2484. ULONG RtPowerManagementVersion=0;
  2485. ULONG RtSystemPowerMode=0;
  2486. DWORD
  2487. __declspec(naked)
  2488. _cdecl
  2489. VPOWERD_Get_Version (
  2490. VOID
  2491. )
  2492. {
  2493. VxDJmp(_VPOWERD_Get_Version);
  2494. }
  2495. POWERRET
  2496. __declspec(naked)
  2497. _cdecl
  2498. VPOWERD_Get_Mode (
  2499. PDWORD pMode
  2500. )
  2501. {
  2502. VxDJmp(_VPOWERD_Get_Mode);
  2503. }
  2504. POWERRET
  2505. __declspec(naked)
  2506. _cdecl
  2507. VPOWERD_Register_Power_Handler (
  2508. POWER_HANDLER Power_Handler,
  2509. DWORD Priority
  2510. )
  2511. {
  2512. VxDJmp(_VPOWERD_Register_Power_Handler);
  2513. }
  2514. // This is the priority that we use when we register with VPOWERD.
  2515. // This is the highest possible priority that can be used.
  2516. // This means that we will be called after everyone else when the machine is
  2517. // suspending, and before everyone else when the machine is resuming.
  2518. // That is exactly what we want.
  2519. #define HIGHESTPRIORITYVPOWERDCLIENT 0xffffff00
  2520. NTSTATUS RtpSetupPowerManagement()
  2521. {
  2522. if ((RtPowerManagementVersion=VPOWERD_Get_Version())==0) {
  2523. // VPOWERD is not loaded. Punt!
  2524. Trap();
  2525. return STATUS_UNSUCCESSFUL;
  2526. }
  2527. if (VPOWERD_Get_Mode(&RtSystemPowerMode)!=PR_SUCCESS) {
  2528. // VPOWERD get mode failed. Punt!
  2529. Trap();
  2530. return STATUS_UNSUCCESSFUL;
  2531. }
  2532. // Register our power handler.
  2533. if (VPOWERD_Register_Power_Handler((POWER_HANDLER)RtpPowerHandler, HIGHESTPRIORITYVPOWERDCLIENT|PHPL_HANDLE_INTS_OFF)!=PR_SUCCESS) {
  2534. Trap();
  2535. return STATUS_UNSUCCESSFUL;
  2536. }
  2537. return STATUS_SUCCESS;
  2538. }
  2539. #endif // UNDER_NT
  2540. #define MEASUREMENTCOUNT 1000
  2541. ULONG CyclesPerRtYield;
  2542. ULONG CyclesPerInt2;
  2543. ULONG CyclesPerInt2FloatSwitch;
  2544. // This routine calls the SwitchRealTimeThreads routine in several different ways
  2545. // in order to measure the overhead involved in switching between realtime threads.
  2546. VOID
  2547. MeasureRealTimeExecutiveOverhead (
  2548. VOID
  2549. )
  2550. {
  2551. ULONG i;
  2552. ULONGLONG starttime, stoptime;
  2553. // Time thread switches.
  2554. // First we time them when RtYield is used to transfer control.
  2555. // Note that we must enable RtRunning in order to get RtYield to accept
  2556. // the request. We turn it on after interrupts are off and then turn
  2557. // it back off before interrupts go on in order to fake out the check
  2558. // in RtYield.
  2559. SaveAndDisableMaskableInterrupts();
  2560. RtRunning=1;
  2561. // Get code/data in the cache.
  2562. RtYield(0, 0);
  2563. RtYield(0, 0);
  2564. starttime=ReadCycleCounter();
  2565. for (i=0; i<MEASUREMENTCOUNT; i++) {
  2566. RtYield(0, 0);
  2567. }
  2568. stoptime=ReadCycleCounter();
  2569. RtRunning=0;
  2570. RestoreMaskableInterrupts();
  2571. CyclesPerRtYield=(ULONG)((stoptime-starttime)/MEASUREMENTCOUNT);
  2572. // Now time them when we directly interrupt to transfer control.
  2573. SaveAndDisableMaskableInterrupts();
  2574. starttime=ReadCycleCounter();
  2575. for (i=0; i<MEASUREMENTCOUNT; i++) {
  2576. RtpSimulateRtInterrupt();
  2577. }
  2578. stoptime=ReadCycleCounter();
  2579. RestoreMaskableInterrupts();
  2580. CyclesPerInt2=(ULONG)((stoptime-starttime)/MEASUREMENTCOUNT);
  2581. // Now time them when we directly interrupt to transfer control but also
  2582. // switch the floating point state.
  2583. activefloatthreadcount++;
  2584. SaveAndDisableMaskableInterrupts();
  2585. starttime=ReadCycleCounter();
  2586. for (i=0; i<MEASUREMENTCOUNT; i++) {
  2587. RtpSimulateRtInterrupt();
  2588. }
  2589. stoptime=ReadCycleCounter();
  2590. RestoreMaskableInterrupts();
  2591. CyclesPerInt2FloatSwitch=(ULONG)((stoptime-starttime)/MEASUREMENTCOUNT);
  2592. activefloatthreadcount--;
  2593. }
  2594. // In order to properly support the APIC hals on NT, I am going to have to significantly change
  2595. // how we obtain and change the system irql levels. On UP hals, this was easy because there
  2596. // is a single global variable that contains the current IRQL level, and the UP hal implemented
  2597. // lazy irql. The variable was NOT connected to any hardware, it was just the desired current
  2598. // IRQL level. When irql changed, the hardware was NOT neccesarily programed, just this global
  2599. // value was changed. If an interrupt hit and IRQL was higher than that interrupt, then the
  2600. // interrupt was queued up for later simulation, and the hardware was programmed to raise the
  2601. // hardware irql level to that indicated in the system irql level global variable. This made
  2602. // faking the IRQL levels for RT threads very easy, as all we needed to do was to change the
  2603. // global IRQL level to what we wanted IRQL to be, and we were done, since interrupts were
  2604. // disabled the whole time anyway, no interrupt would come in - so there was no bad effect of
  2605. // temporarily changing the system irql level to match what the IRQL in the rt thread was. We
  2606. // simply always restored the global irql level variable back to its windows value before
  2607. // we returned to windows.
  2608. // On APIC hals, this is much more complicated. There is not really any lazy irql on the
  2609. // APIC hals. When the IRQL level is changed, it is written to memory, but the memory it is
  2610. // written to is a local APIC hardware register that is used for masking off interrupts. So,
  2611. // when you change irql levels on the APIC hal, you are immediately masking or unmasking
  2612. // interrupts. This means that the global memory location used to store the current irql level
  2613. // is now a hardware register. I can't go off and reprogram the hardware register to an
  2614. // irql level lower than that which it currently contains without asking for lots of grief and
  2615. // pain. It won't work. I need to leave the hardware irql levels untouched, just as happens
  2616. // in the UP hal case. All I want to do really is to change the value that will be returned
  2617. // by system functions that access the current IRQL level, to match what the current RT thread
  2618. // irql level is. Then when we switch back to windows I want those functions to see again the
  2619. // true hardware irql level.
  2620. // So, the solution on an APIC hal, is to remap the pointer the system uses to get to the local
  2621. // APIC hardware from the hardware memory location to a normal page of memory - whenever we
  2622. // switch out of windows. We also load into that page, the IRQL level of the each rt thread
  2623. // when we switch to it. This makes it so that all of the functions that report irql levels
  2624. // will report the proper irql levels for each rt thread when they are called from that thread.
  2625. // When we switch back to windows, we point the memory used to access the local apic, back at
  2626. // the real hardware. We switch this back and forth by modifying the page table entry that
  2627. // is used to map the hal into virtual memory. After each switch, we also have to invalidate
  2628. // the TLBs for that page. We use the INVLPG instruction to do this - so that we only invalidate
  2629. // the entries for that specific page.
  2630. // We can also be more tricky about this, if we want to make sure that no code is trying to
  2631. // change anything on the faked out local apic, by marking the memory page as read only. We
  2632. // can make it so that page that the system uses to access the memory is an alias of a page that
  2633. // we have read write access to, but it only has read access to. Then if any system code runs
  2634. // while we are running an rt thread, that tries to program the local apic, it will fault and we
  2635. // will catch it.
  2636. // A further nasty detail we have to deal with on the APIC hals is that the IRQL level programmed
  2637. // into the hardware does NOT correspond 1 to 1 with IRQL levels that the system APIs understand.
  2638. // This is because there are only 32 official IRQL levels in the system APIs, but the local
  2639. // APICs support 256 interrupts, and have limitations on the depth of their interrupt queing
  2640. // that essentially requires the system to spread the hardware interrupts accross the 256 interrupt
  2641. // levels. This means that the value stored in the APIC hardware register is NOT a simple system
  2642. // IRQL level, so we have to also discover and save whatever the value that gets programmed
  2643. // into the hardware for DISPATCH_LEVEL is. Since for now, rt threads all run at DISPATCH_LEVEL
  2644. // and only DISPATCH_LEVEL, that is the only value we need to track. Currently on the machines
  2645. // I have been investigating, the APIC is programmed to 0x41 for DISPATCH_LEVEL. However,
  2646. // since this can change, we simply record what the system sets it to when we set the IRQL
  2647. // level to DISPATCH_LEVEL. Then the value will always be correct even if the HALs change.
  2648. NTSTATUS
  2649. GetSystemIrqlPointer (
  2650. PKIRQL *ppCurrentIrql
  2651. )
  2652. {
  2653. KIRQL OldIrql;
  2654. PKIRQL pIrql;
  2655. PULONG_PTR Code;
  2656. ULONG_PTR Offset=0;
  2657. BOOL FoundSystemIrql=FALSE;
  2658. // First call KeGetCurrentIrql. This will snap any links to the function.
  2659. KeGetCurrentIrql();
  2660. // Get a pointer to start of the function;
  2661. Code=(PULONG_PTR)KeGetCurrentIrql;
  2662. // Scan for system IRQL memory location.
  2663. while (!FoundSystemIrql) {
  2664. // Make sure that first instruction of that code matches what we expect. If not,
  2665. // then punt.
  2666. switch( (*Code&0xff) ) {
  2667. case 0x0f:
  2668. // We hit this for retail VMM on Win9x and on the NT uniprocessor and ACPI HALs.
  2669. // We also hit this the second time through the loop for debug VMM on Win9x.
  2670. // We also hit this the third time through the loop for the NT MP HAL.
  2671. if (!( ((*Code&0x0000ffff)==0x0000b60f &&
  2672. ((*Code&0x00ff0000)==0x00050000 || (*Code&0x00ff0000)==0x00800000)) ||
  2673. ((*Code&0x0000ffff)==0x0000b70f &&
  2674. ((*Code&0x00ff0000)==0x00050000))
  2675. )) {
  2676. // movzx al, opcode=0f b6 05 addr or opcode=0f b6 80 addr
  2677. return STATUS_UNSUCCESSFUL;
  2678. }
  2679. // Get the memory location of CurrentIrql in vmm. We pull it out of
  2680. // the tail end of this instruction.
  2681. // Skip the opcode.
  2682. Code=(PULONG_PTR)(((PCHAR)Code)+3);
  2683. // Pull out the address. This will be an unligned reference, but thats
  2684. // ok, x86 deals with unaligned references just fine.
  2685. pIrql=(PKIRQL)(*Code+Offset);
  2686. // We have our pointer to system IRQL so break out of the scan loop.
  2687. FoundSystemIrql=TRUE;
  2688. break;
  2689. case 0x6a:
  2690. // We hit this for debug VMM on Win9x.
  2691. if ((*Code&0x0000ffff)!=0x0000046a) {
  2692. return STATUS_UNSUCCESSFUL;
  2693. }
  2694. // If we get here, then it should be debug VMM. Skip to next instruction
  2695. // and recheck. Next instruction should be movzx al with opcode=0f b6 05 addr
  2696. Code+=2;
  2697. break;
  2698. case 0xa1:
  2699. // We hit this for the NT multiprocessor HAL. The first time through the loop.
  2700. // For now we disable support for hals that use the local APIC. We will
  2701. // turn them on once we have them working properly.
  2702. return STATUS_UNSUCCESSFUL;
  2703. // Point at and load the processor offset for the processor we are running on.
  2704. // For now, since we only run on UP, this should always be zero.
  2705. Code=(PULONG_PTR)(((PCHAR)Code)+1);
  2706. // Pull out the offset. This will make one unligned reference, but thats
  2707. // ok, x86 deals with unaligned references just fine.
  2708. Offset=*(PULONG_PTR)(*Code);
  2709. ASSERT ( Offset == 0 );
  2710. // Now point to the next instruction. Should be a shr eax, 0x4.
  2711. Code=(PULONG_PTR)(((PCHAR)Code)+4);
  2712. break;
  2713. case 0xc1:
  2714. // We hit this for NT MP HAL. The second time through the loop.
  2715. if ((*Code&0x00ffffff)!=0x0004e8c1) {
  2716. return STATUS_UNSUCCESSFUL;
  2717. }
  2718. // Move to next instruction. Should be a movzx eax.
  2719. Code=(PULONG_PTR)(((PCHAR)Code)+3);
  2720. break;
  2721. default:
  2722. return STATUS_UNSUCCESSFUL;
  2723. }
  2724. }
  2725. // Now test our pointer and make sure it is correct. If not, then punt.
  2726. if (*pIrql!=KeGetCurrentIrql()) {
  2727. return STATUS_UNSUCCESSFUL;
  2728. }
  2729. // Raise IRQL and test it again.
  2730. KeRaiseIrql(DISPATCH_LEVEL, &OldIrql);
  2731. if (*pIrql!=DISPATCH_LEVEL) {
  2732. return STATUS_UNSUCCESSFUL;
  2733. }
  2734. // Restore IRQL and test it one last time.
  2735. KeLowerIrql(OldIrql);
  2736. if (*pIrql!=OldIrql) {
  2737. return STATUS_UNSUCCESSFUL;
  2738. }
  2739. // We got the pointer, save it away and return success.
  2740. *ppCurrentIrql=pIrql;
  2741. return STATUS_SUCCESS;
  2742. }
  2743. enum ControlCodes {
  2744. CHECKLOADED,
  2745. GETVERSION,
  2746. GETSELECTOR,
  2747. GETBASEADDRESS
  2748. };
  2749. #ifndef UNDER_NT
  2750. DWORD __stdcall RtWin32API(PDIOCPARAMETERS p)
  2751. {
  2752. switch (p->dwIoControlCode) {
  2753. case CHECKLOADED:
  2754. break;
  2755. case GETVERSION:
  2756. // Get version.
  2757. if (!p->lpvOutBuffer || p->cbOutBuffer<4)
  2758. return ERROR_INVALID_PARAMETER;
  2759. *(PDWORD)p->lpvOutBuffer=0x0100;
  2760. if (p->lpcbBytesReturned)
  2761. *(PDWORD)p->lpcbBytesReturned=4;
  2762. break;
  2763. case GETSELECTOR:
  2764. // Get selector.
  2765. if (!p->lpvOutBuffer || p->cbOutBuffer<4)
  2766. return ERROR_INVALID_PARAMETER;
  2767. *(PDWORD)p->lpvOutBuffer=(DWORD)RtRing3Selector;
  2768. if (p->lpcbBytesReturned)
  2769. *(PDWORD)p->lpcbBytesReturned=4;
  2770. break;
  2771. case GETBASEADDRESS:
  2772. // Get base address.
  2773. if (!p->lpvOutBuffer || p->cbOutBuffer<4)
  2774. return ERROR_INVALID_PARAMETER;
  2775. *(PDWORD)p->lpvOutBuffer=(DWORD)&threadswitchcount;
  2776. if (p->lpcbBytesReturned)
  2777. *(PDWORD)p->lpcbBytesReturned=4;
  2778. break;
  2779. default:
  2780. return ERROR_INVALID_PARAMETER;
  2781. }
  2782. return 0;
  2783. }
  2784. #endif
  2785. VOID
  2786. RtpForceAtomic (
  2787. VOID (*AtomicOperation)(PVOID),
  2788. PVOID Context
  2789. )
  2790. {
  2791. ULONG OldPerfInterrupt;
  2792. // Acquire the RT lock.
  2793. SaveAndDisableMaskableInterrupts();
  2794. OldPerfInterrupt=*ApicPerfInterrupt;
  2795. if ((OldPerfInterrupt&(NMI|MASKED))==NMI) {
  2796. DisablePerformanceCounterInterrupt();
  2797. }
  2798. // Call the function that must be run atomically.
  2799. (*AtomicOperation)(Context);
  2800. // Now release the RT lock.
  2801. if ((OldPerfInterrupt&(NMI|MASKED))==NMI) {
  2802. // First unmask the scheduler interrupt.
  2803. RestorePerformanceCounterInterrupt(OldPerfInterrupt);
  2804. // Now check if we have held off the rt scheduler.
  2805. // If so, then update that count and give scheduler control now.
  2806. // We have held off the scheduler if both performance counters
  2807. // are positive for 2 consecutive reads.
  2808. if ((ReadPerformanceCounter(0)&((PERFCOUNTMASK+1)/2))==0 &&
  2809. (ReadPerformanceCounter(1)&((PERFCOUNTMASK+1)/2))==0) {
  2810. if ((ReadPerformanceCounter(0)&((PERFCOUNTMASK+1)/2))==0 &&
  2811. (ReadPerformanceCounter(1)&((PERFCOUNTMASK+1)/2))==0) {
  2812. Trap();
  2813. RtpForceAtomicHoldoffCount++;
  2814. RtYield(0, 0);
  2815. }
  2816. }
  2817. }
  2818. // Now check if we held off maskable interrupts. Either maskable
  2819. // performance counter interrupts, OR maskable apic timer interrupts.
  2820. // We check this by looking at the interrupt request bit in the APIC
  2821. // for our maskable interrupt vector. If it is set, we have held it off.
  2822. // Note that we do NOT need to RtYield in this case since as soon as we
  2823. // restore maskable interrupts, the interrupt will fire by itself.
  2824. if (ReadAPIC(0x200+(ApicTimerVector/32)*0x10)&(1<<(ApicTimerVector%32))) {
  2825. RtpForceAtomicHoldoffCount++;
  2826. }
  2827. // Now restore maskable interrupts.
  2828. RestoreMaskableInterrupts();
  2829. }
  2830. VOID
  2831. RtpFreeRtThreadResources (
  2832. ThreadState *thread
  2833. )
  2834. {
  2835. // Blow away and then release its internal data structures.
  2836. if (thread->FloatState!=NULL) {
  2837. RtlZeroMemory(thread->FloatBase, FLOATSTATESIZE+FXALIGN);
  2838. ExFreePool(thread->FloatBase);
  2839. }
  2840. #ifdef GUARD_PAGE
  2841. RtlZeroMemory(thread->StackBase+1024, thread->Statistics->StackSize<<12);
  2842. FreePages(thread->StackBase, 0);
  2843. #else
  2844. RtlZeroMemory(thread->StackBase, thread->Statistics->StackSize<<12);
  2845. ExFreePool(thread->StackBase);
  2846. #endif
  2847. RtlZeroMemory(thread->Statistics, sizeof(ThreadStats));
  2848. ExFreePool(thread->Statistics);
  2849. RtlZeroMemory(thread, sizeof(ThreadState));
  2850. ExFreePool(thread);
  2851. }
  2852. VOID
  2853. RtpProcessDeadThreads (
  2854. VOID
  2855. )
  2856. {
  2857. ThreadState *thread;
  2858. // See if there are any threads to clean up. If not, then exit.
  2859. thread=RtDeadThreads;
  2860. if (thread==NULL) {
  2861. return;
  2862. }
  2863. // Now atomically grab the list of threads to be cleaned up.
  2864. while (RtpCompareExchange(&(ULONG)RtDeadThreads, (ULONG)NULL, (ULONG)thread)!=(ULONG)NULL) {
  2865. // If we get here, then the compare exchange failed because either another
  2866. // thread was added to the list since we read RtDeadThreads,
  2867. // or another Windows thread cleaned up the dead thread list and
  2868. // there is nothing to do anymore.
  2869. // Reread RtDeadThreads - see if there are threads to clean up, if so
  2870. // try to claim the list again.
  2871. thread=RtDeadThreads;
  2872. if (thread==NULL) {
  2873. return;
  2874. }
  2875. }
  2876. // When we get here, thread is pointing to the head of a list of dead threads
  2877. // that need to be cleaned up. This list is guaranteed to not be touched by
  2878. // anyone else while we are processing it.
  2879. // Walk through the list freeing all of the thread resources in the list.
  2880. {
  2881. ThreadState *nextthread;
  2882. while (thread!=NULL) {
  2883. nextthread=thread->next;
  2884. RtpFreeRtThreadResources(thread);
  2885. thread=nextthread;
  2886. }
  2887. }
  2888. }
  2889. ThreadState *
  2890. RtpGetThreadStateFromHandle (
  2891. HANDLE RtThreadHandle
  2892. )
  2893. {
  2894. ThreadState *thread;
  2895. KIRQL OldIrql;
  2896. // Acquire the thread list spinlock.
  2897. KeAcquireSpinLock(&RtThreadListSpinLock,&OldIrql);
  2898. // Find the thread whose handle matches RtThreadHandle.
  2899. thread=windowsthread;
  2900. while (thread->ThreadHandle!=RtThreadHandle) {
  2901. thread=thread->next;
  2902. // Check if we have searched the whole list. If so, punt.
  2903. if (thread==windowsthread) {
  2904. thread=NULL;
  2905. break;
  2906. }
  2907. }
  2908. // Release the thread list spinlock.
  2909. KeReleaseSpinLock(&RtThreadListSpinLock, OldIrql);
  2910. return thread;
  2911. }
  2912. // WARNING! The following 2 functions work correctly only if they are called
  2913. // by functions that HAVE a stack frame!
  2914. #ifndef UNDER_NT
  2915. ULONG
  2916. __inline
  2917. ReturnAddress (
  2918. VOID
  2919. )
  2920. {
  2921. __asm mov eax, [ebp+4]
  2922. }
  2923. #endif
  2924. ULONG
  2925. __inline
  2926. AddressofReturnAddress (
  2927. VOID
  2928. )
  2929. {
  2930. __asm mov eax, ebp
  2931. __asm add eax, 4
  2932. }
  2933. // This function transfers control to the real time executive.
  2934. // It logs the appropriate counters and timestamp before transfering
  2935. // control and again just after control returns. Those logs can
  2936. // be used to determine the overhead involved in transfering control.
  2937. BOOL RtpTransferControl(
  2938. WORD State,
  2939. ULONG Data,
  2940. BOOL (*DoTransfer)(PVOID),
  2941. PVOID Context
  2942. )
  2943. {
  2944. BOOL ControlTransferred;
  2945. ULONG OldPerfInterrupt;
  2946. #ifdef MASKABLEINTERRUPT
  2947. ULONG OldExtIntInterrupt;
  2948. ULONG OldTimerInterrupt;
  2949. ULONG OldTpr;
  2950. #endif
  2951. // Assume success. If we are running.
  2952. ControlTransferred=RtRunning;
  2953. // It is an error to call RtpTransferControl if the realtime executive is not
  2954. // running. Punt.
  2955. if (!ControlTransferred) {
  2956. Trap();
  2957. return ControlTransferred;
  2958. }
  2959. #ifdef MASKABLEINTERRUPT
  2960. // Make sure no interrupts happen between masking the realtime executive
  2961. // interrupt and transfering control to the executive.
  2962. // However we also must make sure no interrupts get queued up in the processor
  2963. // behind a disable interrupts. So, we do things in a particular order.
  2964. // First we disable the external interrupts. This is typically what a
  2965. // CLI would normally disable on 9x. This will prevent the scheduler from
  2966. // taking control the rest of the code. However it may not be.
  2967. // If we are yielding out of an rt thread, this will already be masked.
  2968. {
  2969. ULONG CheckIntrInterrupt;
  2970. ULONG CheckTimerInterrupt;
  2971. ULONG CheckPerfInterrupt;
  2972. ULONG LoopLimit;
  2973. LoopLimit=0;
  2974. // First read and save all of the interrupt states.
  2975. // Ignore the Delivery Status bit. We do not care if it is
  2976. // set or not - and we do NOT want it to lock up our loop by
  2977. // causing a mismatch when we are checking for the mask
  2978. // First wait until none of the interrupts are send pending.
  2979. while (TRUE) {
  2980. OldExtIntInterrupt=*ApicIntrInterrupt;
  2981. OldTimerInterrupt=*ApicTimerInterrupt;
  2982. OldPerfInterrupt=*ApicPerfInterrupt;
  2983. #ifdef DEBUG
  2984. // ADD checks here on states of all of the local apic interrupts.
  2985. // If they do not match what we expect, then someone else is programming
  2986. // the local apic state and WE ARE THEREFORE BROKEN.
  2987. #endif
  2988. if (!((OldExtIntInterrupt|OldTimerInterrupt|OldPerfInterrupt)&SENDPENDING)) {
  2989. break;
  2990. }
  2991. if (!LoopLimit) {
  2992. SendPendingCount++;
  2993. }
  2994. if (LoopLimit++>1000) {
  2995. Break();
  2996. }
  2997. }
  2998. SendPendingLoopCount+=LoopLimit;
  2999. // Now mask all of those interrupts.
  3000. while (TRUE) {
  3001. *ApicIntrInterrupt=OldExtIntInterrupt|MASKED;
  3002. // Mask the timer interrupt so if we are RT yielding out of windows and it
  3003. // fires, we eat it and it doesn't cause us to prematurely leave our
  3004. // precious realtime threads. :-) :-) If we are yielding out of an
  3005. // rt thread this will already be masked.
  3006. *ApicTimerInterrupt=OldTimerInterrupt|MASKED;
  3007. // Mask the RT executive interrupt.
  3008. // We do this so we can guarantee the exact location inside this routine where
  3009. // control is transfered to the real time executive.
  3010. *ApicPerfInterrupt=OldPerfInterrupt|MASKED;
  3011. // Now read the current states.
  3012. CheckIntrInterrupt=*ApicIntrInterrupt;
  3013. CheckTimerInterrupt=*ApicTimerInterrupt;
  3014. CheckPerfInterrupt=*ApicPerfInterrupt;
  3015. // Loop until the current states match the set states.
  3016. if (CheckIntrInterrupt==(OldExtIntInterrupt|MASKED) &&
  3017. CheckTimerInterrupt==(OldTimerInterrupt|MASKED) &&
  3018. CheckPerfInterrupt==(OldPerfInterrupt|MASKED)) {
  3019. break;
  3020. }
  3021. else {
  3022. TransferControlReMaskCount++;
  3023. }
  3024. }
  3025. if (LoopLimit++>1000) {
  3026. Break();
  3027. }
  3028. }
  3029. #else
  3030. SaveAndDisableMaskableInterrupts();
  3031. // Mask the RT executive interrupt.
  3032. // We do this so we can guarantee the exact location inside this routine where
  3033. // control is transfered to the real time executive.
  3034. // NOTE!! We must handle cases where maskable interrupt hits NOW after
  3035. // masking interrupts but before masking them at the APIC. In that
  3036. // case the interrupt was pending and then got masked. Make SURE
  3037. // we do the right thing. Apic may generate a SPURIOUS interrupt in
  3038. // that case.
  3039. SaveAndDisablePerformanceCounterInterrupt(&OldPerfInterrupt);
  3040. #endif
  3041. #ifdef MASKABLEINTERRUPT
  3042. // Now make sure that no matter what anyone does with the interrupt flag
  3043. // between now and the end of switchrealtimethreads, our 2 interrupts
  3044. // will not fire. Unless that someone messes with the local apic as well.
  3045. OldTpr=ReadAPIC(APICTPR);
  3046. WriteAPIC( APICTPR, 0xff);
  3047. SaveAndDisableMaskableInterrupts();
  3048. #endif
  3049. // Validate parameters.
  3050. // Decide if we are really going to transfer control.
  3051. if (!(*DoTransfer)(Context)) {
  3052. #ifdef MASKABLEINTERRUPT
  3053. RestoreMaskableInterrupts();
  3054. // Restore original task priority register state.
  3055. WriteAPIC( APICTPR, OldTpr);
  3056. #endif
  3057. // Restore the original performance counter interrupt state.
  3058. RestorePerformanceCounterInterrupt(OldPerfInterrupt);
  3059. #ifdef MASKABLEINTERRUPT
  3060. // Restore original timer interrupt state.
  3061. *ApicTimerInterrupt=OldTimerInterrupt;
  3062. *ApicIntrInterrupt=OldExtIntInterrupt;
  3063. #else
  3064. RestoreMaskableInterrupts();
  3065. #endif
  3066. // At this point we know we will NOT transfer control for the reason
  3067. // requested.
  3068. ControlTransferred=FALSE;
  3069. // Note that we now need the complexity that we have in RtpForceAtomic
  3070. // to check for cases when we have lost our interrupt because it was
  3071. // masked, and get the proper control transfered.
  3072. // If we have dropped our normal interrupt for timeslicing on the
  3073. // floor, then even though we are NOT going to transfer control for
  3074. // the reason we tested for in this routine, we MUST still transfer
  3075. // control because we masked our interrupt and it hit while it was
  3076. // masked and thus got dropped on the floor. (Since both the timer
  3077. // and the performance counter interrupts are edge triggered and we
  3078. // can't change them to level triggered.) So, we now check if we
  3079. // missed our interrupt, and if so, we override the State and Data
  3080. // passed in, and force the transfer control to happen anyway, with
  3081. // a State of RUN and Data of zero. That is the state for normal
  3082. // timeslice interrupts.
  3083. if (currentthread!=windowsthread) {
  3084. // We have held off the scheduler if both performance counters
  3085. // are positive for 2 consecutive reads.
  3086. if ((ReadPerformanceCounter(0)&((PERFCOUNTMASK+1)/2))==0 &&
  3087. (ReadPerformanceCounter(1)&((PERFCOUNTMASK+1)/2))==0) {
  3088. if ((ReadPerformanceCounter(0)&((PERFCOUNTMASK+1)/2))==0 &&
  3089. (ReadPerformanceCounter(1)&((PERFCOUNTMASK+1)/2))==0) {
  3090. RtpTransferControlHoldoffCount++;
  3091. State=RUN;
  3092. Data=0;
  3093. SaveAndDisableMaskableInterrupts();
  3094. goto yieldtimeslice;
  3095. }
  3096. }
  3097. }
  3098. else {
  3099. // This is tougher to figure out. For now, we do not handle this
  3100. // case.
  3101. // I need to see if the counter rolled over while in this routine,
  3102. // and if there is no interrupt pending, and if I did not service
  3103. // the interrupt itself.
  3104. }
  3105. return ControlTransferred;
  3106. }
  3107. yieldtimeslice:
  3108. // Load state/data slots for current thread.
  3109. currentthread->state=State;
  3110. currentthread->data=Data;
  3111. // Log the appropriate counters/timestamps.
  3112. // The fastest way to get control to the realtime executive is to do a
  3113. // software NMI. Run a software interrupt instruction. This will NOT enable the hardware
  3114. // to hold off other NMIs while servicing this software NMI, but we have
  3115. // all other NMIs masked. If there is a way for other NMIs to hit then
  3116. // we will either have to revert to a method that generates a hardware NMI - or
  3117. // we will need a mechanism to detect and prevent reentrant NMIs.
  3118. // With local APICs, it IS possible for an IOAPIC or another local APIC to
  3119. // send an NMI to us that would reenter this software NMI. Note that if we switch
  3120. // IDTs we can detect if a NMI fires while we are in our NMI handler.
  3121. // One nice benefit from using a software NMI is that do not lose the
  3122. // current counts in the performance counters. We can use that to track the
  3123. // overhead nicely.
  3124. RtpSimulateRtInterrupt();
  3125. // When control returns here, the real time executive will have unmasked the
  3126. // PerformanceCounter interrupt for us. We do not need to do unmask it.
  3127. // The realtime executive will also have set the ApicTimerInterrupt properly
  3128. // as well as the task priority register.
  3129. // Log the counters/timestamps again - this is done immediately after control is
  3130. // returned to this function.
  3131. // Restore the original interrupt state.
  3132. RestoreMaskableInterrupts();
  3133. return ControlTransferred;
  3134. }
  3135. BOOL
  3136. RtpTrue (
  3137. PVOID Context
  3138. )
  3139. {
  3140. return TRUE;
  3141. }
  3142. BOOL
  3143. RtpYieldNeeded (
  3144. PVOID Context
  3145. )
  3146. {
  3147. PYIELDTIME Time=(PYIELDTIME)Context;
  3148. if ( (RtTime() - Time->Mark) < Time->Delta) {
  3149. return TRUE;
  3150. }
  3151. else {
  3152. return FALSE;
  3153. }
  3154. }
  3155. BOOL
  3156. RtpAtomicExit (
  3157. PVOID Context
  3158. )
  3159. {
  3160. ULONG PerfInterrupt;
  3161. KIRQL OldIrql;
  3162. // First see if the SpinLock is clear. If so, then everything is
  3163. // hunky dory and we allow control to transfer.
  3164. // Note that this SpinLock is only used to protect the list for a SINGLE
  3165. // processor. This is NOT multiprocessor safe. That is OK because
  3166. // we are going to have separate lists of realtime threads on a per
  3167. // processor basis. If we even port this implementation to multiple
  3168. // procs - which on NT in my opinion we should NOT.
  3169. // Although there is a tradeoff there. We could actually get dpc's
  3170. // firing on both processors with this when we would not if we used
  3171. // my other NT implementation. There is actually a cross over point
  3172. // between the 2 implementations depending on the number of processors
  3173. // and how many processors are used for RT, and how heavily they
  3174. // are loaded down with RT threads.
  3175. // The key to running this nicely on a multiproc system is to ensure
  3176. // that you sync the processors so the realtime threads are running
  3177. // as far out of phase as possible - ideally 180 degrees out of phase.
  3178. // That gives you the best overall system interrupt latency. And,
  3179. // with a light rt load allows you to run DPCs on both processors.
  3180. // The very nice thing about the other implementation is that it gets
  3181. // you user mode realtime support.
  3182. if (RtThreadListSpinLock==0) {
  3183. return TRUE;
  3184. }
  3185. // If we get here, then someone is holding the lock. So, queue up behind
  3186. // them.
  3187. KeAcquireSpinLock(&RtThreadListSpinLock, &OldIrql);
  3188. // Now we are holding the lock and the scheduler interrupt will be unmasked
  3189. // since we will have RtYielded to the other thread and back.
  3190. // There may be other threads queued up on this lock behind us - since we
  3191. // lost control to the scheduler when we tried to acquire the spinlock.
  3192. // Note however that maskable interrupts should still be disabled.
  3193. PerfInterrupt=*ApicPerfInterrupt;
  3194. #ifdef DEBUG
  3195. // Check that the scheduler interrupt is enabled.
  3196. if (PerfInterrupt&MASKED) {
  3197. Trap();
  3198. return FALSE;
  3199. }
  3200. // Check that the SpinLock is held.
  3201. if (!RtThreadListSpinLock) {
  3202. Trap();
  3203. return FALSE;
  3204. }
  3205. // Check that maskable interrupts are disabled.
  3206. #endif
  3207. // Grab the scheduler lock again and release the spinlock.
  3208. DisablePerformanceCounterInterrupt();
  3209. KeReleaseSpinLock(&RtThreadListSpinLock, OldIrql);
  3210. // Now either the SpinLock is free and the scheduler is still disabled,
  3211. // which means that there was noone blocked on the spinlock behind us,
  3212. // OR the scheduler is enabled and the state of the spinlock is indeterminate
  3213. // in which case we should start over completely anyway.
  3214. PerfInterrupt=*ApicPerfInterrupt;
  3215. if (RtThreadListSpinLock==0 && (PerfInterrupt&MASKED)) {
  3216. return TRUE;
  3217. }
  3218. return FALSE;
  3219. }
  3220. VOID
  3221. AddRtThread (
  3222. ThreadState *thread
  3223. )
  3224. {
  3225. // If we were passed a pointer to a thread handle, fill it in now.
  3226. // This is atomic with regard to the creation and running of this thread.
  3227. // The handle can be used within the realtime thread as well as by
  3228. // any non rt code. It is guaranteed to be set properly before the
  3229. // thread starts to run.
  3230. if (thread->pThreadHandle!=NULL) {
  3231. *thread->pThreadHandle=thread->ThreadHandle;
  3232. }
  3233. // Add thread to the rt thread list.
  3234. thread->next=windowsthread;
  3235. thread->previous=windowsthread->previous;
  3236. windowsthread->previous=thread;
  3237. thread->previous->next=thread;
  3238. // Update the floating point/mmx thread count.
  3239. if (thread->FloatState!=NULL) {
  3240. activefloatthreadcount++;
  3241. }
  3242. // Update our RT thread count.
  3243. RtThreadCount++;
  3244. // Now unmask the realtime scheduler interrupt if the thread count is 2.
  3245. if (RtThreadCount>1) {
  3246. // Start the performance counters and unmask the local apic timer
  3247. // interrupt. This starts the realtime executive task switching.
  3248. WriteAPIC(APICTIMER, ApicTimerVector|UNMASKED|PERIODIC);
  3249. }
  3250. }
  3251. // This function runs when a realtime thread exits.
  3252. VOID
  3253. RtpThreadExit (
  3254. VOID
  3255. )
  3256. {
  3257. // This function is tricky.
  3258. // The problem is that when this function is called, we need to remove the
  3259. // thread from the list of real time threads. With our current implementation,
  3260. // that means that we need to grab the RtThreadListSpinLock. However, I do NOT
  3261. // want to deal with releasing the spinlock from within the realtime
  3262. // executive thread switcher - switchrealtimethreads.
  3263. // So, that means that I need a way to atomically grab the spinlock, so that
  3264. // I will block if someone else owns the spinlock until they release it. However,
  3265. // I must do this so that when I grab the spinlock, I am guaranteed that NOONE
  3266. // else will try to grab it after me, before I have transfered control atomically
  3267. // up to the realtime executive. This is so that I can RELEASE the spinlock just
  3268. // before transfering control up to the executive and be guaranteed that I will
  3269. // not give control to anyone else who has blocked on the spinlock.
  3270. // That way I can use the spinlock to protect the list, but release it in
  3271. // the realtime thread just before control is atomically transfered to the
  3272. // executive.
  3273. // The executive can then take this thread out of the list put it on the dead
  3274. // thread list and switch to the next thread to run.
  3275. while (!RtpTransferControl(EXIT, 0, RtpAtomicExit, NULL))
  3276. ;
  3277. }
  3278. // Add a failsafe for thread switching the realtime threads -
  3279. // use the PIIX3 to generate NMIs instead of SMIs and that is
  3280. // our backup if the perfcounter NMI interrupt does not work.
  3281. // IDEA! Actually, we CAN get these realtime threads to run on
  3282. // Pentium class machines. We use the chipset on the motherboard
  3283. // to generate the NMI that drives the scheduler. That will work
  3284. // not quite as well as the perf counters, but it will work.
  3285. // We could use that to drive the 1ms or 2ms or 0.5ms initial
  3286. // NMI that takes control away from windows and transfers it to the
  3287. // first real time thread. That would bypass the problem we
  3288. // currently have of not having a perf counter that is just a simple
  3289. // cycle counter. Right now we have the problem that the cycle
  3290. // counter we have stops when we hit a halt instruction. Also,
  3291. // the instruction counter also stops when we hit a halt instruction.
  3292. // Unfortunately, it is not completely that simple. After looking
  3293. // closer at the documentation, the only interrupt that I can get
  3294. // to fire from the chipset is SMI, and furthermore, the counter is
  3295. // only an 8 bit counter. In order to get the resolution I want
  3296. // I would have to set it to count single PCI cycles. So, the
  3297. // longest period that would have would be 8usec. That would mean
  3298. // taking an SMI every 8 usec. or over 100,000 times/sec. That
  3299. // is a little excessive. 125,000 times/sec with a 33MHz clock.
  3300. // Furthermore, I would have to write an smi handler that would
  3301. // then generate an NMI. That would be possible but even more work,
  3302. // since then I would have to write and load a SMI handler - which
  3303. // would mean trying to take control of that away from the BIOS.
  3304. // Not necessarily a good idea. Plus it would likely be very tricky
  3305. // and potentially impossible to wrest control of the SMI handler
  3306. // away from the BIOS especially if it is using the special bits
  3307. // that keep the PIIX3 from letting anyone else load the SMI
  3308. // memory.
  3309. #pragma warning( disable: 4035 )
  3310. ULONG
  3311. __inline
  3312. RtpCompareExchange (
  3313. ULONG *destination,
  3314. ULONG source,
  3315. ULONG value
  3316. )
  3317. {
  3318. ASSERT( destination!=NULL );
  3319. ASSERT( source!=value );
  3320. __asm {
  3321. mov eax,value
  3322. mov ecx,source
  3323. mov edx,destination
  3324. lock cmpxchg [edx],ecx
  3325. jnz done
  3326. mov eax,ecx
  3327. done:
  3328. }
  3329. }
  3330. #define cmpxchg8 __asm _emit 0xf0 __asm _emit 0x0f __asm _emit 0xc7 __asm _emit 0x0f
  3331. ULONGLONG __cdecl RtCompareExchange8(ULONGLONG *destination, ULONGLONG source, ULONGLONG value)
  3332. {
  3333. ASSERT( destination!=NULL );
  3334. ASSERT( source!=value );
  3335. __asm {
  3336. mov edi,destination
  3337. mov ebx,[ebp + 0x8 + TYPE destination]
  3338. mov ecx,[ebp + 0x8 + TYPE destination + TYPE source/2]
  3339. mov eax,[ebp + 0x8 + TYPE destination + TYPE source]
  3340. mov edx,[ebp + 0x8 + TYPE destination + TYPE source + TYPE value / 2]
  3341. cmpxchg8
  3342. jnz done
  3343. mov edx,ecx
  3344. mov eax,ebx
  3345. done:
  3346. }
  3347. }
  3348. #pragma warning( default: 4035 )
  3349. NTSTATUS
  3350. RtpWriteVersion (
  3351. PULONG Version
  3352. )
  3353. {
  3354. __try {
  3355. *Version=0x00090000;
  3356. }
  3357. __except(EXCEPTION_EXECUTE_HANDLER) {
  3358. return STATUS_INVALID_PARAMETER;
  3359. }
  3360. return STATUS_SUCCESS;
  3361. }
  3362. // If the real time executive is running, this function returns
  3363. // STATUS_SUCCESS. If for some reason the real time executive
  3364. // cannot run on the current machine then STATUS_NOT_SUPPORTED
  3365. // is returned.
  3366. // If the pointer to the version number is non NULL, then the
  3367. // version information for the currently loaded real time executive
  3368. // is returned. The version information will be returned regardless
  3369. // of whether the real time executive can run or not.
  3370. // If this function is called from a real time thread, then the version
  3371. // pointer MUST either be NULL, or it MUST point to a local variable on
  3372. // that real time thread's stack. Otherwise this function will return
  3373. // STATUS_INVALID_PARAMETER.
  3374. // We enable stack frames for RtVersion so that AddressofReturnAddress works properly.
  3375. #pragma optimize("y", off)
  3376. NTSTATUS
  3377. RtVersion (
  3378. PULONG Version
  3379. )
  3380. {
  3381. if (Version!=NULL) {
  3382. // We must validate this pointer before we go writing into it.
  3383. // This is complicated by the fact that this must be RT safe as well.
  3384. // The solution to make this check simple is to impose the requirement
  3385. // that if this function is called from an RT thread, then the version
  3386. // pointer MUST point to a local variable on THAT rt thread's stack.
  3387. // Otherwise we simply return STATUS_INVALID_PARAMETER.
  3388. if (currentthread==windowsthread) {
  3389. // This is a Windows thread.
  3390. // Wrap the version number write inside an exception handler.
  3391. NTSTATUS Status;
  3392. Status=RtpWriteVersion(Version);
  3393. if (Status!=STATUS_SUCCESS) {
  3394. return Status;
  3395. }
  3396. }
  3397. else {
  3398. // This is an RT thread. Check if pointer is to a local var on this
  3399. // RT thread stack. Note that we make sure to exclude the thread return
  3400. // address and its 2 parameters from the allowable space for this local
  3401. // variable. We also exclude all of the space on the stack required to
  3402. // call this function. Everything else is fair game.
  3403. if ((ULONG)Version<(AddressofReturnAddress()+sizeof(VOID(*)(VOID))+sizeof(Version)) ||
  3404. (ULONG)Version>=((ULONG)(currentthread->StackBase+1024)+(currentthread->Statistics->StackSize<<12) -
  3405. (sizeof(VOID(*)(VOID))+sizeof(PVOID)+sizeof(ThreadStats *))) ) {
  3406. return STATUS_INVALID_PARAMETER;
  3407. }
  3408. *Version=0x00090000;
  3409. }
  3410. }
  3411. #ifndef UNDER_NT
  3412. // Make sure we are being called from a WDM driver. If not, we are
  3413. // not available.
  3414. if (ReturnAddress()<WDMADDRESSSPACE) {
  3415. return STATUS_NOT_SUPPORTED;
  3416. }
  3417. #endif
  3418. if (RtRunning) {
  3419. return STATUS_SUCCESS;
  3420. }
  3421. return STATUS_NOT_SUPPORTED;
  3422. }
  3423. #pragma optimize("", on)
  3424. // We can calibrate - and should calibrate, the threadswitching time.
  3425. // We do this by measuring how long it takes to repeatedly call the threadswitch
  3426. // routine. Note that we should do this in many different ways so that we can
  3427. // get a good measure of the different paths through the routine.
  3428. // We should call it straight - with a software interrupt. We should call it the fast
  3429. // way where we simply set things up on the stack and jump straight to the
  3430. // routine.
  3431. // We should call it with floatingpointcount set to force the floatingpoint
  3432. // save and restore. We should call it without that.
  3433. // Ideally we calibrate all of the standard paths through the routine.
  3434. // We should also simulate the hardware interrupt version as well - both the
  3435. // nmi and the maskable interrupt entrance. Then we can know very acurately
  3436. // how we perform.
  3437. // For all these measurements, build a histogram. Ideally we dump those measurements
  3438. // to a file.
  3439. // We also need to track the results in whatever standard way we are going to
  3440. // track statistics on run times. Then we can use whatever tools we build for use
  3441. // with those with these measurements of critical code paths.
  3442. // Note that this can enable us to measure overhead without having to measure the
  3443. // overhead internally to the routine. That will enable us to keep the routine
  3444. // as fast as possible. The less we have to read counters/write counters etc
  3445. // the faster we will be able to switch threads.
  3446. // Calibrate RtYield, RtpTransferControl,
  3447. BOOLEAN
  3448. RtThread (
  3449. VOID
  3450. )
  3451. {
  3452. if (RtRunning && currentthread!=windowsthread) {
  3453. return TRUE;
  3454. }
  3455. return FALSE;
  3456. }
  3457. // IDEA: I can know exactly which data is likely unreliable when I am calibrating
  3458. // the CPU. If 2 successive measurements are farther apart than I think they
  3459. // should be, then drop that pair - the hardware read and the timestamp read,
  3460. // do another hardware read and timestamp read. Keep the previous timestamp
  3461. // read just to validate if this new hardware read and timestamp read are valid.
  3462. // If so, then log them as good data and continue with the latest timestamp read
  3463. // used to check the next pair of readings. I think this validation technique
  3464. // can really improve the speed and results of my cpu calibration.
  3465. // Note, that I can use this to throw away bad data points in the set AFTER all of the
  3466. // measurements are done.
  3467. // Write a clock tracking realtime thread. Track the APIC vs CPU clocks and the
  3468. // APIC vs the motherboard timer clock and the CPU vs motherboard clock.
  3469. NTSTATUS
  3470. RtCreateThread (
  3471. ULONGLONG Period,
  3472. ULONGLONG Duration,
  3473. ULONG Flags,
  3474. ULONG StackSize,
  3475. RTTHREADPROC RtThread,
  3476. PVOID pRtThreadContext,
  3477. PHANDLE pRtThreadHandle
  3478. )
  3479. {
  3480. ThreadState *thread;
  3481. ULONG *stack;
  3482. ThreadStats *statistics;
  3483. ULONG FloatSave[(FLOATSTATESIZE+FXALIGN)/sizeof(ULONG)];
  3484. KIRQL OldIrql;
  3485. // Make sure we NULL out handle if a valid handle passed in.
  3486. // This way we clear handle for all error cases.
  3487. if (pRtThreadHandle!=NULL) {
  3488. *pRtThreadHandle=NULL;
  3489. }
  3490. #ifndef UNDER_NT
  3491. // First make sure we are being called from a WDM driver. If not, punt.
  3492. if (ReturnAddress()<WDMADDRESSSPACE) {
  3493. return STATUS_NOT_SUPPORTED;
  3494. }
  3495. #endif
  3496. // Now make sure the realtime executive is running.
  3497. if (!RtRunning) {
  3498. return STATUS_NOT_SUPPORTED;
  3499. }
  3500. // Make sure we are being called from a windows thread.
  3501. if (currentthread!=windowsthread) {
  3502. return STATUS_UNSUCCESSFUL;
  3503. }
  3504. // Free any resources held by dead realtime threads.
  3505. // Dead realtime threads are threads that have exited since either
  3506. // RtCreateThread or RtDestroyThread were last called.
  3507. RtpProcessDeadThreads();
  3508. // Validate parameters.
  3509. // For now Period must be 1 msec or greater.
  3510. // For now it also must be an exact multiple of a MSEC.
  3511. if (Period<1*MSEC || Period%MSEC) {
  3512. Trap();
  3513. return STATUS_INVALID_PARAMETER_1;
  3514. }
  3515. // For now Duration must be 1 usec or greater.
  3516. if (Duration>=Period || (Duration>0 && Duration<1*USEC)) {
  3517. Trap();
  3518. return STATUS_INVALID_PARAMETER_2;
  3519. }
  3520. // Don't accept any flags except the ones we know about.
  3521. // For now we do NOT accept INSTRUCTIONS flag.
  3522. if (Flags&~(USESFLOAT|USESMMX|CPUCYCLES/*|INSTRUCTIONS*/)) {
  3523. Trap();
  3524. return STATUS_INVALID_PARAMETER_3;
  3525. }
  3526. // Stacksize must be between 4k and 32k inclusive.
  3527. if (StackSize<1 || StackSize>8) {
  3528. Trap();
  3529. return STATUS_INVALID_PARAMETER_4;
  3530. }
  3531. #ifndef UNDER_NT
  3532. if ((ULONG)RtThread<WDMADDRESSSPACE) {
  3533. Trap();
  3534. // This could be STATUS_BAD_INITIAL_PC but that would be too
  3535. // informative. We don't want non WDM drivers creating real time
  3536. // threads.
  3537. return STATUS_NOT_SUPPORTED;
  3538. }
  3539. #endif
  3540. // TODO: Get the name of the driver that owns the return address. Stuff
  3541. // it in our ThreadState structure. Make sure that the RtDestroyThread
  3542. // comes from the same driver. Use that to track who has created what threads.
  3543. // Idea: set a debug register to catch writes to a certain spot in memory
  3544. // above where we will fault.
  3545. // Even when I have a guard page at the bottom of the stack, I STILL need
  3546. // a task gate on the page fault handler. Since otherwise I will simply
  3547. // triple fault the processor and it will reboot - since if the realtime
  3548. // threads run ring0, and I fault, I stay on the ring 0 stack and that
  3549. // has just page faulted and will page fault again when attempting to
  3550. // service the page fault, so will double fault, which will then fault again
  3551. // which will reboot.
  3552. // However, if I have a double fault handler that has a task gate, then
  3553. // I can differentiate between stack generated page faults and other
  3554. // page faults. The stack based ones will all hit the double fault
  3555. // handler while the other ones will hit the page fault handler.
  3556. // OR, an interesting idea: just put a task gate on the stack segment fault
  3557. // handler. Then it will work. Either the page fault, or the stack segment
  3558. // will fault when we reach the edge. Task gate those, so you can not
  3559. // double fault.
  3560. // Stack overflow - 1) if a debugger, stop in debugger pointing to code where it died,
  3561. // 2) kill the thread. Any operation - single step or go - should kill the
  3562. // thread. In retail, just kill the thread.
  3563. // Allocate a thread state block.
  3564. thread=(ThreadState *)ExAllocatePool( NonPagedPool, sizeof(ThreadState) );
  3565. if (thread==NULL) {
  3566. return STATUS_NO_MEMORY;
  3567. }
  3568. #ifdef GUARD_PAGE
  3569. // Allocate a stack for this thread.
  3570. stack=thread->StackBase=(ULONG *)ReservePages(PR_SYSTEM, StackSize+1, PR_FIXED);
  3571. if ((LONG)stack==(-1)) {
  3572. ExFreePool(thread);
  3573. return STATUS_NO_MEMORY;
  3574. }
  3575. // Commit memory to all but first page of stack. This gives us a guard
  3576. // page at bottom of stack. So we will page fault if a realtime thread
  3577. // blows their stack. Actually, if a realtime thread blows their stack
  3578. // we will double fault and we MUST have a task gate on the double fault
  3579. // handler.
  3580. if (!CommitPages(((ULONG)stack>>12)+1, StackSize, PD_FIXEDZERO, 0, PC_FIXED|PC_WRITEABLE)) {
  3581. FreePages(stack, 0);
  3582. ExFreePool(thread);
  3583. return STATUS_NO_MEMORY;
  3584. }
  3585. #else
  3586. // Allocate a stack for this thread.
  3587. stack=thread->StackBase=(ULONG *)ExAllocatePool( NonPagedPool, StackSize<<12 );
  3588. if (stack==NULL) {
  3589. ExFreePool(thread);
  3590. return STATUS_NO_MEMORY;
  3591. }
  3592. #endif
  3593. // Allocate a statistics block for this thread.
  3594. statistics=thread->Statistics=(ThreadStats *)ExAllocatePool( NonPagedPool, sizeof(ThreadStats) );
  3595. if (statistics==NULL) {
  3596. #ifdef GUARD_PAGE
  3597. FreePages(stack, 0);
  3598. #else
  3599. ExFreePool(stack);
  3600. #endif
  3601. ExFreePool(thread);
  3602. return STATUS_NO_MEMORY;
  3603. }
  3604. // Initialize the statistics block.
  3605. RtlZeroMemory(statistics, sizeof(ThreadStats));
  3606. statistics->Period=Period;
  3607. statistics->Duration=Duration;
  3608. statistics->Flags=Flags;
  3609. statistics->StackSize=StackSize;
  3610. #if 0
  3611. // Reserve a page that we can map as a read only page for the statistics block.
  3612. // That will keep people from being able to trash the statistics.
  3613. readonlystats=CreateReadOnlyStatisticsPage(statistics);
  3614. if (readonlystats==NULL) {
  3615. ExFreePool(statistics);
  3616. #ifdef GUARD_PAGE
  3617. FreePages(stack, 0);
  3618. #else
  3619. ExFreePool(stack);
  3620. #endif
  3621. ExFreePool(thread);
  3622. return STATUS_NO_MEMORY;
  3623. }
  3624. #endif
  3625. // Allocate space for thread float/MMX state if required.
  3626. // TODO: Use NonPagedPoolCacheAligned as a parameter and get rid of FloatBase.
  3627. // I don't need it except to make sure things are 8 byte aligned.
  3628. // Cache Aligning will do that for me.
  3629. thread->FloatBase=NULL;
  3630. thread->FloatState=NULL;
  3631. if (Flags&USESFLOAT || Flags&USESMMX) {
  3632. thread->FloatBase=ExAllocatePool( NonPagedPool, FLOATSTATESIZE+FXALIGN );
  3633. if (thread->FloatBase==NULL) {
  3634. ExFreePool(statistics);
  3635. #ifdef GUARD_PAGE
  3636. FreePages(stack, 0);
  3637. #else
  3638. ExFreePool(stack);
  3639. #endif
  3640. ExFreePool(thread);
  3641. return STATUS_NO_MEMORY;
  3642. }
  3643. RtlZeroMemory(thread->FloatBase, FLOATSTATESIZE+FXALIGN);
  3644. // Now 16 byte align the floating point state pointer so fxsave/fxrstor can
  3645. // be used if supported.
  3646. thread->FloatState=(PVOID)(((ULONG)thread->FloatBase+(FXALIGN-1))&~(FXALIGN-1));
  3647. #ifdef DEBUG
  3648. // Make sure the enable floating point MMX instructions bit is set in CR4.
  3649. // If not, then the fxsave and fxrstor instructions will not work properly.
  3650. if ((CPUFeatures&FXSR) && !(ReadCR4()&OSFXSR)) {
  3651. Trap();
  3652. }
  3653. #endif
  3654. {
  3655. ULONG SaveCR0, NewCR0;
  3656. // We don't want vmcpd or the windows thread switcher to intervene while
  3657. // we are setting up a pristine floating point state.
  3658. SaveAndDisableMaskableInterrupts();
  3659. // Save off CR0 state.
  3660. NewCR0=SaveCR0=ReadCR0();
  3661. // Now make sure we won't fault running FP instructions.
  3662. // EM=0, NE=1, ET=1, TS=0, MP=1.
  3663. NewCR0&=~(FPUMASK);
  3664. NewCR0|=FPUEXCEPTION|FPU387COMPATIBLE|FPUMONITOR;
  3665. WriteCR0(NewCR0);
  3666. // Now save a valid initial floating point state for this thread.
  3667. SaveThreadFloatState((PVOID)((((ULONG)FloatSave)+FXALIGN-1)&~(FXALIGN-1)));
  3668. __asm fninit;
  3669. SaveThreadFloatState(thread->FloatState);
  3670. RestoreThreadFloatState((PVOID)((((ULONG)FloatSave)+FXALIGN-1)&~(FXALIGN-1)));
  3671. // Restore original CR0 state.
  3672. WriteCR0(SaveCR0);
  3673. RestoreMaskableInterrupts();
  3674. }
  3675. }
  3676. // Now everything is ready to go, allocate our CPU and see if we have enough.
  3677. // If not, punt.
  3678. RtCpuAllocatedPerMsec+=(ULONG)(Duration/(Period/MSEC));
  3679. if (RtCpuAllocatedPerMsec>MSEC) {
  3680. RtCpuAllocatedPerMsec-=(ULONG)(Duration/(Period/MSEC));
  3681. RtpFreeRtThreadResources(thread);
  3682. return STATUS_INSUFFICIENT_RESOURCES;
  3683. }
  3684. // Get a unique handle for this thread.
  3685. thread->ThreadHandle=RtpCreateUniqueThreadHandle();
  3686. // Save off output pointer to handle.
  3687. thread->pThreadHandle=pRtThreadHandle;
  3688. // Set initial state and data for this thread.
  3689. thread->state=RUN;
  3690. thread->data=0;
  3691. // Setup StackSize so we can use it as an offset into stack.
  3692. // First add guard page to size, then turn StackSize into count
  3693. // of DWORDs instead of pages.
  3694. #ifdef GUARD_PAGE
  3695. StackSize+=1;
  3696. #endif
  3697. StackSize<<=10;
  3698. // Setup the thread function parameters on the stack.
  3699. // C calling convention.
  3700. stack[--StackSize]=(ULONG)statistics; // Statistics
  3701. stack[--StackSize]=(ULONG)pRtThreadContext; // Context
  3702. // Now setup the return address of our function.
  3703. // We point the return address at the internal destroy rt thread function.
  3704. // That function will take the realtime thread out of the list of active
  3705. // realtime threads, and will put it on the dead thread list, so its
  3706. // resources will be freed the next time RtCreateThread or RtDestroyThread
  3707. // are called.
  3708. stack[--StackSize]=(ULONG)RtpThreadExit;
  3709. // Now setup the IRET so we will run the thread function.
  3710. // Actually there is fast way to detect if we are switching a windows
  3711. // thread or an rt thread. Simply use the CS stored
  3712. // on the stack. If it is the CS for the RT descriptor, then we
  3713. // came in on a rt thread, if it is not, then it was windows. That
  3714. // is faster since we do NOT have to push the flags - which is slow,
  3715. // and we can do it with a stack segment relative read, and a
  3716. // compare (read) with a code segment descriptor. So we can do
  3717. // the test at the very beginning of our interrupt handler if
  3718. // we want - and it will be FAST.
  3719. // However, I DO want to eventually run them at CPL=1 or CPL=2 or
  3720. // CPL=3, so we will have to do something about IOPL then anyway.
  3721. #ifdef MASKABLEINTERRUPT
  3722. stack[--StackSize]=0x00000046|IF; // EFLAGS: IOPL=0 IF=1
  3723. #else
  3724. stack[--StackSize]=0x00000046; // EFLAGS: IOPL=0 IF=0
  3725. #endif
  3726. stack[--StackSize]=RtThreadCS; // CS
  3727. stack[--StackSize]=(ULONG)RtThread; // EIP
  3728. stack[--StackSize]=0; // EAX
  3729. // Initialize the thread block.
  3730. thread->esp=(ULONG)(stack+StackSize);
  3731. thread->ss=RealTimeSS;
  3732. thread->ds=RealTimeDS;
  3733. thread->es=RealTimeDS;
  3734. thread->fs=0;
  3735. thread->gs=0;
  3736. thread->ecx=0;
  3737. thread->edx=0;
  3738. thread->ebx=0;
  3739. thread->ebp=0;
  3740. thread->esi=0;
  3741. thread->edi=0;
  3742. thread->irql=DISPATCH_LEVEL;
  3743. // Add this thread to list of threads to run.
  3744. // This MUST be atomic!
  3745. KeAcquireSpinLock(&RtThreadListSpinLock,&OldIrql);
  3746. RtpForceAtomic((VOID(*)(PVOID))AddRtThread, (PVOID)thread);
  3747. #ifdef WAKE_EVERY_MS
  3748. #ifndef UNDER_NT
  3749. // On NT, we cannot call SetTimerResolution from DISPATCH_LEVEL
  3750. // because it calls ExSetTimerResolution which is paged.
  3751. // Unfortunately, this makes syncronization of setting the system timer
  3752. // resolution to 1ms with the creation and deletion of realtime
  3753. // threads more complicated. See comment below for an explanation of
  3754. // how we syncronize this on NT.
  3755. if (!WakeCpuFromC2C3EveryMs && RtThreadCount>1) {
  3756. WakeCpuFromC2C3EveryMs=TRUE;
  3757. SetTimerResolution(1);
  3758. }
  3759. #endif
  3760. #endif
  3761. KeReleaseSpinLock(&RtThreadListSpinLock, OldIrql);
  3762. #ifdef WAKE_EVERY_MS
  3763. #ifdef UNDER_NT
  3764. // On NT, our SetTimerResolution, ReleaseTimerResolution calls are synchronized
  3765. // differently than they are on 9x. We cannot call them while holding our
  3766. // RtThreadListSpinLock. In addition, I really did NOT want to add a mutex for
  3767. // syncronization of those calls because we currently do not have a mutex that we
  3768. // grab in RtCreateThread or in RtDestroyThread and I do not want to start using
  3769. // one.
  3770. // After looking at how ExSetTimerResolution works on NT, and thinking about this
  3771. // problem, I came up with the following synchronization algorithm that will work
  3772. // acceptably on NT. First, the critical thing is that we MUST always have the
  3773. // system timer resolution set to 1ms if there are any realtime threads running.
  3774. // The one thing that we do NOT want is to have 1 or more realtime threads running
  3775. // while the system timer resolution is more than 1ms. If we sometimes in very rare
  3776. // situations, leave the system timer set to 1ms when there are no realtime threads
  3777. // running, that is OK - as long as we retry turning off 1ms resolution after more
  3778. // realtime threads are created and then destroyed.
  3779. // The algorithm I have implemented has the above characteristics. It guarantees
  3780. // because of the way that ExSetTimerResolution works on NT, that if there
  3781. // are realtime threads, then the system timer resolution WILL be set to 1ms. It
  3782. // can in rare situations allow the system timer resolution to stay set to 1ms even
  3783. // when there are no realtime threads left running.
  3784. // The algorithm is the following: When we are creating a realtime thread,
  3785. // if RtThreadCount is greater than 1, and the system timer resolution has not
  3786. // been set, then note that we are setting the resolution to 1ms, then call
  3787. // SetTimerResolution and when the call completes, note that the system timer
  3788. // resolution has been set to 1ms. In this way we will only ever set the system
  3789. // timer resolution to 1ms if it has not already been set or started to be set to
  3790. // 1ms.
  3791. // When we are destroying a realtime thread, if there are no realtime threads left
  3792. // running, and we have already completed setting the system timer resolution to
  3793. // 1 ms, then mark the system timer as not set to 1ms and then turn it off. Note that
  3794. // there is a window between when we mark the system timer as turned off, and when
  3795. // ExSetTimerResolution actually grabs its internal mutex. This means that an
  3796. // RtCreateThread call can run before we actually have turned off the system timer
  3797. // and it will decide to turn on the system timer again before we have turned it off.
  3798. // This is GOOD. Because ExSetTimerResolution works by keeping track of the number of
  3799. // times a resolution has been set, and the number of times it has been released. It
  3800. // then only releases whatever the minimum setting has been to the current time, when
  3801. // ALL of the set calls have been matched by a release call. This means that if we
  3802. // do an additional set call before we have run our release call, that the system
  3803. // timer resolution will stay at a resolution at least as small as our resolution the
  3804. // whole time, and the release call will NOT release the resolution because we made
  3805. // an additional set call before the release. If the release call runs before the
  3806. // set call, that is OK as well, since the set call will reset the resolution back
  3807. // down to 1ms.
  3808. // The point is to make sure that if there are realtime threads, the system timer
  3809. // resolution gets set to 1ms or stays at 1ms. That is why we mark the system timer
  3810. // as turned off before we actually turn it off - so that we WILL turn it on the
  3811. // next time RtCreateThread is called. Again the point is to not ever let the system
  3812. // timer NOT be set to 1ms if there are realtime threads.
  3813. // The only thing about the current algorithm that is not perfect, is that there is
  3814. // also a window where we can leave the system resolution set to 1 ms even though there
  3815. // are no realtime threads running. This can only happen if an RtDestroyThread call
  3816. // runs before the RtCreateThread call has completed and destroys the just created
  3817. // realtime thread. If that RtDestroyThread call runs after the realtime thread has
  3818. // been added to the list, and after we have started to set the system timer resolution
  3819. // to 1ms, but before we have completed setting the system timer resolution to 1ms,
  3820. // then we will NOT clear the setting of the system timer resolution to 1ms in that
  3821. // RtDestroyThread call, and when both calls have completed, we will have no realtime
  3822. // threads running, but the system timer resolution will have been left at 1ms.
  3823. // This is NOT a problem. First of all, the current client - kmixer - never calls
  3824. // RtDestroyThread until AFTER RtCreateThread has completed. Second of all, even if
  3825. // this happened, all that means is the next time a realtime thread is created, we
  3826. // will note that the system timer resolution is already 1ms, and will NOT set it down
  3827. // to 1ms since it is already there. Furthermore, when that realtime thread is
  3828. // destroyed, we WILL release the resolution. This works because the state of the
  3829. // WakeCpuFromC2C3EveryMs variable is always CORRECT. If we get into this situation
  3830. // where we destroy the only realtime thread in the system before we complete setting
  3831. // the system timer resolution to 1ms, WakeCpuFromC2C3EveryMs will indicate that the
  3832. // system timer resolution is still set to 1ms - and the system timer resolution WILL
  3833. // be set to 1ms.
  3834. // Again the CRITICAL requirement that this algorithm DOES MEET, is that we guarantee
  3835. // that whenever there are realtime threads running the system timer resolution is
  3836. // 1ms. And except in very very rare and hard to produce circumstances, whenever
  3837. // there are no realtime threads, the system timer resolution is released. In those
  3838. // cases when it is not released, its release will again be attempted if further
  3839. // realtime threads are created and destroyed. Furthermore the current realtime client
  3840. // will NEVER cause this case to hit, so we will ALWAYS turn off system timer
  3841. // properly.
  3842. // Don't change this code unless you GUARANTEE that whenever there are realtime threads
  3843. // the system timer resolution is 1ms.
  3844. if (RtThreadCount>1 && InterlockedCompareExchange(&WakeCpuFromC2C3EveryMs, 1, 0)==0) {
  3845. SetTimerResolution(1);
  3846. InterlockedIncrement(&WakeCpuFromC2C3EveryMs);
  3847. }
  3848. #endif
  3849. #endif
  3850. #ifndef MASKABLEINTERRUPTS
  3851. // This hack is not longer safe for the maskable interrupt version of
  3852. // rt.sys. We may have one of our interrupts queued up on the
  3853. // WARNING: BROKEN IBM MACHINE SPECIFIC HACK FOLLOWS.
  3854. // Check if the local APIC is wedged. This happens if the ISR bit for
  3855. // our maskable realtime scheduler bit is set. That bit should only
  3856. // ever be set while we are in our interrupt service routine. If it
  3857. // is set now, then the scheduler is stuck - at least until we get
  3858. // the performance counter backup working.
  3859. // If the ISR bit is set for our maskable interrupt then we need to
  3860. // clear it.
  3861. // We only EOI the APIC if our ISR bit is set.
  3862. {
  3863. ULONG count=0;
  3864. while (ReadAPIC(0x100+(ApicTimerVector/32)*0x10)&(1<<(ApicTimerVector%32))) {
  3865. // Since this fix is for broken machines, trap so in debug code I can see how
  3866. // many machines hit this.
  3867. Trap();
  3868. // We have to EOI the APIC to try to get our ISR bit cleared.
  3869. WriteAPIC(APICEOI,0);
  3870. count++;
  3871. // At most we would have to clear all the ISR bits that are higher
  3872. // priority than ours before ours should go clear. This in reality
  3873. // is overkill but worst case of completely broken APIC/software, this many
  3874. // EOIs might be necessary.
  3875. if (ApicTimerVector+count>255) {
  3876. Trap();
  3877. break;
  3878. }
  3879. }
  3880. }
  3881. #endif
  3882. return STATUS_SUCCESS;
  3883. }
  3884. // This function is called from a windows thread to destroy a real
  3885. // time thread. This function should NOT be called from a real
  3886. // time thread - that is because it is currently freeing memory
  3887. // and calling functions that are NOT realtime safe.
  3888. // If we modify the implementation so that we simply put the
  3889. // destroyed thread on a list, and process the memory releases
  3890. // from our own private windows thread, then we can make this
  3891. // API safe for real time threads.
  3892. // For now, since RtCreateThread can only be called from windows
  3893. // threads, we leave this API as callable only from windows threads
  3894. // as well.
  3895. // The only way to destroy a real time thread from within the
  3896. // realtime thread itself is to return from it.
  3897. // We do NOT want to be able to kill the windows thread.
  3898. // We currently will not be able to do that since the windows
  3899. // thread stack does not ever return to the destroy thread
  3900. // code.
  3901. // IDEA: Try just jumping to the int3 handler with the stack setup
  3902. // to point to the spot you want the debugger to break. Make it so
  3903. // when there are errors of any kind, we break on the instruction after
  3904. // the call. As long as debuggers actually stop on an int3 even if they
  3905. // do not see one there, this will work. ie: if they are not picky and
  3906. // don't double check to make sure the previous instruction was an int3
  3907. // then this will work. Then I do not need to get control after the
  3908. // debugger. The debugger should treat the int3 as a call to tell it
  3909. // STOP at that location - even if no int 3 was embedded in the instruction
  3910. // stream. Then I can fix things up and get things to stop where I want.
  3911. NTSTATUS
  3912. RtDestroyThread (
  3913. HANDLE RtThreadHandle
  3914. )
  3915. {
  3916. ThreadState *thread;
  3917. KIRQL OldIrql;
  3918. #ifndef UNDER_NT
  3919. // First make sure we are being called from a WDM driver. If not, punt.
  3920. if (ReturnAddress()<WDMADDRESSSPACE) {
  3921. return STATUS_NOT_SUPPORTED;
  3922. }
  3923. #endif
  3924. // Punt if we are not running on this machine.
  3925. if (!RtRunning) {
  3926. Trap();
  3927. return STATUS_NOT_SUPPORTED;
  3928. }
  3929. // Make sure we are being called from a windows thread.
  3930. if (currentthread!=windowsthread) {
  3931. return STATUS_UNSUCCESSFUL;
  3932. }
  3933. // Find the thread whose handle has been passed in.
  3934. thread=RtpGetThreadStateFromHandle(RtThreadHandle);
  3935. if (thread==NULL) {
  3936. Trap();
  3937. return STATUS_INVALID_HANDLE;
  3938. }
  3939. // If we get here, then thread is pointing to the thread state
  3940. // of the thread that needs to be destroyed.
  3941. // It is an error to destroy the windows thread. Make sure
  3942. // we are not attempting to destroy the windows thread. We must
  3943. // make this check in case someone passes in a handle matching
  3944. // the windows thread handle.
  3945. if (thread==windowsthread) {
  3946. Trap();
  3947. return STATUS_UNSUCCESSFUL;
  3948. }
  3949. // Now make sure that the thread is being destroyed by the same driver
  3950. // that created it. If not, then punt.
  3951. // At this point, everything is set to kill the thread. Only thing
  3952. // we must ensure is that the real time thread is not holding any
  3953. // spinlocks when it is removed from the list of real time threads.
  3954. // Atomically remove the realtime thread from list of realtime threads.
  3955. KeAcquireSpinLock(&RtThreadListSpinLock,&OldIrql);
  3956. RtpForceAtomic((VOID(*)(PVOID))RemoveRtThread, (PVOID)thread);
  3957. #ifdef WAKE_EVERY_MS
  3958. #ifndef UNDER_NT
  3959. // On NT, we cannot call ReleaseTimerResolution from DISPATCH_LEVEL
  3960. // because it calls ExSetTimerResolution which is paged.
  3961. if (WakeCpuFromC2C3EveryMs && RtThreadCount<=1) {
  3962. WakeCpuFromC2C3EveryMs=FALSE;
  3963. ReleaseTimerResolution(1);
  3964. }
  3965. #endif
  3966. #endif
  3967. KeReleaseSpinLock(&RtThreadListSpinLock, OldIrql);
  3968. #ifdef WAKE_EVERY_MS
  3969. #ifdef UNDER_NT
  3970. if (RtThreadCount<=1 && InterlockedCompareExchange(&WakeCpuFromC2C3EveryMs, 0, 2)==2) {
  3971. ReleaseTimerResolution(1);
  3972. }
  3973. #endif
  3974. #endif
  3975. // Free this threads resources.
  3976. RtpFreeRtThreadResources(thread);
  3977. // Now free any resources held by dead realtime threads.
  3978. // Dead realtime threads are threads that have exited since either
  3979. // RtCreateThread or RtDestroyThread were last called.
  3980. RtpProcessDeadThreads();
  3981. return STATUS_SUCCESS;
  3982. }
  3983. VOID
  3984. RtYield (
  3985. ULONGLONG Mark,
  3986. ULONGLONG Delta
  3987. )
  3988. {
  3989. WORD State;
  3990. //ASSERT( &Delta == &Mark+sizeof(Mark) );
  3991. YIELDTIME Time;
  3992. Time.Mark=Mark;
  3993. Time.Delta=Delta;
  3994. // It is an error to call RtYield if the realtime executive is not
  3995. // running. Punt.
  3996. if (!RtRunning) {
  3997. Trap();
  3998. return;
  3999. }
  4000. // Load our command to the realtime executive.
  4001. State=YIELD;
  4002. if (0==Mark && 0==Delta) {
  4003. State=RUN;
  4004. RtpTransferControl(State, 0, RtpTrue, NULL);
  4005. return;
  4006. }
  4007. else if (currentthread==windowsthread) {
  4008. // It is an error to RtYield for a non zero length of time from
  4009. // Windows.
  4010. Trap();
  4011. return;
  4012. }
  4013. // Send the appropriate command to the realtime executive and transfer control.
  4014. RtpTransferControl(State, (ULONG)&Time, RtpYieldNeeded, (PVOID)&Time);
  4015. }
  4016. NTSTATUS
  4017. RtAdjustCpuLoad(
  4018. ULONGLONG Period,
  4019. ULONGLONG Duration,
  4020. ULONGLONG Phase,
  4021. ULONG Flags
  4022. )
  4023. {
  4024. #ifndef UNDER_NT
  4025. // First make sure we are being called from a WDM driver. If not, punt.
  4026. if (ReturnAddress()<WDMADDRESSSPACE) {
  4027. return STATUS_NOT_SUPPORTED;
  4028. }
  4029. #endif
  4030. // Now make sure the realtime executive is running.
  4031. if (!RtRunning) {
  4032. return STATUS_NOT_SUPPORTED;
  4033. }
  4034. // Make sure we are being called from a realtime thread.
  4035. if (currentthread==windowsthread) {
  4036. return STATUS_UNSUCCESSFUL;
  4037. }
  4038. // Validate parameters.
  4039. // For now Period must be 1 msec or greater.
  4040. // For now it also must be an exact multiple of a MSEC.
  4041. if (Period<1*MSEC || Period%MSEC) {
  4042. Trap();
  4043. return STATUS_INVALID_PARAMETER_1;
  4044. }
  4045. // For now Duration must be 1 usec or greater.
  4046. if (Duration>=Period || (Duration>0 && Duration<1*USEC)) {
  4047. Trap();
  4048. return STATUS_INVALID_PARAMETER_2;
  4049. }
  4050. // For now we do NOT accept any changes in the Flags parameters from the
  4051. // settings passed in at thread creation.
  4052. if (Flags!=currentthread->Statistics->Flags) {
  4053. Trap();
  4054. return STATUS_INVALID_PARAMETER_3;
  4055. }
  4056. // Now make sure that we have sufficient CPU to succeed this allocation and
  4057. // update the CPU allocation for this thread.
  4058. RtCpuAllocatedPerMsec+=(ULONG)(Duration/(Period/MSEC))-(ULONG)(currentthread->Statistics->Duration/(currentthread->Statistics->Period/MSEC));
  4059. if (RtCpuAllocatedPerMsec>MSEC) {
  4060. RtCpuAllocatedPerMsec-=(ULONG)(Duration/(Period/MSEC))-(ULONG)(currentthread->Statistics->Duration/(currentthread->Statistics->Period/MSEC));
  4061. return STATUS_INSUFFICIENT_RESOURCES;
  4062. }
  4063. // Update the thread's statistics with the new Period and Duration.
  4064. currentthread->Statistics->Period=Period;
  4065. currentthread->Statistics->Duration=Duration;
  4066. return STATUS_SUCCESS;
  4067. }
  4068. NTSTATUS
  4069. RtSystemInfo(
  4070. ULONG Processor,
  4071. SystemInfo * pSystemInfo
  4072. )
  4073. {
  4074. CPUINFO thecpu;
  4075. ULONG MaxIndex;
  4076. #ifndef UNDER_NT
  4077. // First make sure we are being called from a WDM driver. If not, punt.
  4078. if (ReturnAddress()<WDMADDRESSSPACE) {
  4079. return STATUS_NOT_SUPPORTED;
  4080. }
  4081. #endif
  4082. // Validate our parameters.
  4083. if (Processor) {
  4084. return STATUS_INVALID_PARAMETER_1;
  4085. }
  4086. if (pSystemInfo==NULL) {
  4087. return STATUS_INVALID_PARAMETER_2;
  4088. }
  4089. if (!GetCpuId(0, &thecpu)) {
  4090. return STATUS_UNSUCCESSFUL;
  4091. }
  4092. // Clear all of the initial values.
  4093. // We also use this as an good time to ensure that the pointer we were
  4094. // passed is actually valid.
  4095. __try {
  4096. RtlZeroMemory(pSystemInfo, sizeof(SystemInfo));
  4097. }
  4098. __except (EXCEPTION_EXECUTE_HANDLER) {
  4099. return STATUS_INVALID_PARAMETER_2;
  4100. }
  4101. MaxIndex=thecpu.eax;
  4102. // On 9x, ProcessorCount is always 1 for now.
  4103. pSystemInfo->ProcessorCount=1;
  4104. // Load the architecture value.
  4105. pSystemInfo->CpuArchitecture=X86;
  4106. // Load the manufacturer value.
  4107. if (thecpu.ebx==0x756e6547 && thecpu.edx==0x49656e69 && thecpu.ecx==0x6c65746e ) {
  4108. pSystemInfo->CpuManufacturer=INTEL;
  4109. }
  4110. if (thecpu.ebx==0x68747541 && thecpu.edx==0x69746e65 && thecpu.ecx==0x444d4163 ) {
  4111. pSystemInfo->CpuManufacturer=AMD;
  4112. }
  4113. // If its supported, get the family/model/stepping and features info.
  4114. if (MaxIndex) {
  4115. GetCpuId(1, &thecpu);
  4116. pSystemInfo->CpuFamily=(thecpu.eax>>8)&0xf;
  4117. pSystemInfo->CpuModel=(thecpu.eax>>4)&0xf;
  4118. pSystemInfo->CpuStepping=thecpu.eax&0xf;
  4119. pSystemInfo->CpuFeatures=thecpu.edx;
  4120. }
  4121. // Get the unique processor ID number.
  4122. if (MaxIndex>=3 /* && (pSystemInfo->CpuFeatures&(1<<18)) */ ) {
  4123. // The top 32 bits of the 96 bit processor id is the value returned
  4124. // in eax from running a cpuid instruction with 1 in eax.
  4125. // This value is still left in thecpu.eax.
  4126. pSystemInfo->ProcessorID[1]=thecpu.eax;
  4127. GetCpuId(3, &thecpu);
  4128. pSystemInfo->ProcessorID[0]=((ULONGLONG)thecpu.edx<<32)|thecpu.ecx;
  4129. }
  4130. // Get the extended features information on AMD systems.
  4131. pSystemInfo->CpuExtendedFeatures=0;
  4132. // Load the CPU speed and system bus speed information.
  4133. pSystemInfo->CpuCyclesPerMsec=RtCpuCyclesPerUsec*1000;
  4134. pSystemInfo->SystemBusCyclesPerMsec=RtSystemBusCyclesPerUsec*1000;
  4135. // Load the CPU allocation information if available.
  4136. if (windowsthread!=NULL &&
  4137. RtCpuAllocatedPerMsec>=(ULONG)windowsthread->Statistics->Duration) {
  4138. pSystemInfo->ReservedCpuPerMsec=RtCpuAllocatedPerMsec-(ULONG)windowsthread->Statistics->Duration;
  4139. if (pSystemInfo->ReservedCpuPerMsec>(ULONG)MSEC) {
  4140. pSystemInfo->ReservedCpuPerMsec=(ULONG)MSEC;
  4141. }
  4142. }
  4143. if (windowsthread!=NULL) {
  4144. KIRQL OldIrql;
  4145. ThreadState* thread;
  4146. pSystemInfo->UsedCpuPerMsec=0;
  4147. thread=windowsthread;
  4148. KeAcquireSpinLock(&RtThreadListSpinLock,&OldIrql);
  4149. while(thread->next!=windowsthread) {
  4150. thread=thread->next;
  4151. pSystemInfo->UsedCpuPerMsec+=(ULONG)(thread->Statistics->DurationRunLastPeriod/(thread->Statistics->Period/MSEC));
  4152. }
  4153. KeReleaseSpinLock(&RtThreadListSpinLock, OldIrql);
  4154. }
  4155. if (RtRunning && windowsthread!=NULL ) {
  4156. pSystemInfo->AvailableCpuPerMsec=(ULONG)MSEC-pSystemInfo->ReservedCpuPerMsec;
  4157. if (pSystemInfo->AvailableCpuPerMsec>=(ULONG)windowsthread->Statistics->Duration) {
  4158. pSystemInfo->AvailableCpuPerMsec-=(ULONG)windowsthread->Statistics->Duration;
  4159. }
  4160. else {
  4161. pSystemInfo->AvailableCpuPerMsec=0;
  4162. }
  4163. }
  4164. return STATUS_SUCCESS;
  4165. }
  4166. PVOID
  4167. RtAddLogEntry (
  4168. ULONG Size
  4169. )
  4170. {
  4171. ULONG PrintLocation, NextLocation;
  4172. // For now the Size MUST be 16 bytes always. We can support integral multiples of 16
  4173. // bytes, but then we will have to deal with buffer alignment and wrapping issues.
  4174. if (!RtLog || Size!=RT_LOG_ENTRY_SIZE) {
  4175. return NULL;
  4176. }
  4177. NextLocation=RtLog->WriteLocation;
  4178. do {
  4179. PrintLocation=NextLocation;
  4180. NextLocation=InterlockedCompareExchange(&RtLog->WriteLocation, PrintLocation+RT_LOG_ENTRY_SIZE, PrintLocation);
  4181. } while (PrintLocation!=NextLocation);
  4182. // Now we clear out the opposite half of the print buffer. We do this all in kernel mode.
  4183. // This means that we have data only in 1/2 of the buffer. As we add new data, we
  4184. // delete the old data. We do the deletion of data in kernel mode so that we only
  4185. // need to read data from user mode. I do NOT want user mode code to be writing to
  4186. // this buffer. User mode code can read out of the output buffer, but NOT write into
  4187. // it. This means we MUST both fill and clear this buffer ourselves. Since user
  4188. // mode code is dependent on the fact that all slots will be marked as having
  4189. // NODATA in them until they have been completely loaded with data, at which point
  4190. // they will be marked with something other than NODATA. We guarantee that
  4191. // every slot we are loading starts as NODATA by simply clearing the print slots
  4192. // in kernel mode before we fill them. The easiest way to do this is to start
  4193. // by marking all entries in the buffer as NODATA, and then by continuing to make
  4194. // sure that for every print slot we are going to fill with data, we clear the corresponding
  4195. // print slot halfway around the buffer.
  4196. // That simple algorithm guarantees that every slot starts out marked as NODATA and
  4197. // then transitions to some other state after it is filled.
  4198. ((ULONG *)RtLog->Buffer)[((PrintLocation+RtLog->BufferSize/2)%RtLog->BufferSize)/sizeof(ULONG)]=NODATA;
  4199. PrintLocation%=RtLog->BufferSize;
  4200. return RtLog->Buffer+PrintLocation;
  4201. }
  4202. #ifndef UNDER_NT
  4203. #pragma warning( disable : 4035 )
  4204. pVpdRtData
  4205. SendVpdRtInfo (
  4206. VOID
  4207. )
  4208. {
  4209. VMMCall( _VPOWERD_RtInfo );
  4210. }
  4211. #pragma warning( default : 4035 )
  4212. VOID
  4213. InitializeVPOWERD (
  4214. VOID
  4215. )
  4216. {
  4217. pVpdRtData VpdData;
  4218. VpdData=SendVpdRtInfo();
  4219. *VpdData->pFunction=TurnOffLocalApic;
  4220. }
  4221. #pragma warning( disable : 4035 )
  4222. pNtRtData
  4223. SendNtKernRtInfo (
  4224. VOID
  4225. )
  4226. {
  4227. VMMCall( _NtKernRtInfo );
  4228. }
  4229. pVmmRtData
  4230. SendVmmRtInfo (
  4231. VOID
  4232. )
  4233. {
  4234. VMMCall( _VmmRtInfo );
  4235. }
  4236. #pragma warning( default : 4035 )
  4237. VOID
  4238. InitializeNT (
  4239. VOID
  4240. )
  4241. {
  4242. pNtRtData NtData;
  4243. pVmmRtData VmmData;
  4244. NtData=SendNtKernRtInfo();
  4245. *NtData->pBase=ApicBase;
  4246. *NtData->pFunction1=RtpTransferControl;
  4247. *NtData->pFunction2=RtpForceAtomic;
  4248. *NtData->pThread=&(volatile ULONG)currentthread;
  4249. // Do this LAST - so other values are valid before we set this.
  4250. *NtData->pRtCs=RtExecCS;
  4251. VmmData=SendVmmRtInfo();
  4252. *VmmData->pBase=ApicBase;
  4253. *VmmData->pFunction=RtpForceAtomic;
  4254. // Do this LAST - so other values are valid before we set this.
  4255. *VmmData->pRtCs=RtExecCS;
  4256. }
  4257. #endif
  4258. #ifdef UNDER_NT
  4259. ULONGLONG OriginalAcquireCode;
  4260. ULONGLONG OriginalReleaseCode;
  4261. VOID
  4262. __declspec(naked)
  4263. PatchAcquire (
  4264. VOID
  4265. )
  4266. {
  4267. __asm{
  4268. push RtKfAcquireSpinLock
  4269. ret
  4270. int 3
  4271. int 3
  4272. }
  4273. }
  4274. VOID
  4275. __declspec(naked)
  4276. PatchRelease (
  4277. VOID
  4278. )
  4279. {
  4280. __asm {
  4281. push RtKfReleaseSpinLock
  4282. ret
  4283. int 3
  4284. int 3
  4285. }
  4286. }
  4287. #if 0
  4288. VOID
  4289. FASTCALL
  4290. __declspec(naked)
  4291. OriginalRelease (
  4292. IN PKSPIN_LOCK SpinLock
  4293. )
  4294. {
  4295. __asm {
  4296. nop
  4297. nop
  4298. nop
  4299. nop
  4300. nop
  4301. nop
  4302. nop
  4303. nop
  4304. nop
  4305. nop
  4306. nop
  4307. nop
  4308. nop
  4309. nop
  4310. nop
  4311. nop
  4312. }
  4313. }
  4314. NTSTATUS
  4315. RtpSetupOriginalReleaseSpinlock (
  4316. PULONGLONG ReleaseAddress
  4317. )
  4318. {
  4319. PULONGLONG OriginalReleaseAddress, OriginalReleaseAlias;
  4320. PHYSICAL_ADDRESS OriginalReleasePhysicalAddress;
  4321. // First get the virtual addresse of OriginalRelease.
  4322. OriginalReleaseAddress=(PULONGLONG)OriginalRelease;
  4323. // Make sure the code they point to starts like we expect it to. If not, punt.
  4324. OriginalReleaseCode=*ReleaseAddress;
  4325. if ( ! ((OriginalAcquireCode==0xc6ffdff024a0c033 && OriginalReleaseCode==0xf0241588fa9cc933) || // UP HAL
  4326. (OriginalAcquireCode==0x05c7fffe0080158b && OriginalReleaseCode==0x888ac933c28ac033) || // APIC HAL
  4327. (OriginalAcquireCode==0xc6ffdff024a0c033 && OriginalReleaseCode==0xf0243d80cab60f9c)) // ACPI HAL
  4328. ) {
  4329. return STATUS_UNSUCCESSFUL;
  4330. }
  4331. // Now alias the memory with our own writable pointer. So we can
  4332. // patch the code to jump to our routines.
  4333. ReleasePhysicalAddress=MmGetPhysicalAddress(ReleaseAddress);
  4334. ReleaseAlias=MmMapIoSpace(ReleasePhysicalAddress, 16, FALSE);
  4335. if (!ReleaseAlias) {
  4336. return STATUS_UNSUCCESSFUL;
  4337. }
  4338. // Now patch the routines. Note that this code is not MP safe.
  4339. // Currently we will not be called except on uniprocessor machines.
  4340. SaveAndDisableMaskableInterrupts();
  4341. InterlockedCompareExchange64(AcquireAlias, *(PULONGLONG)PatchAcquire, OriginalAcquireCode);
  4342. InterlockedCompareExchange64(ReleaseAlias, *(PULONGLONG)PatchRelease, OriginalReleaseCode);
  4343. RestoreMaskableInterrupts();
  4344. // Release our alias mappings.
  4345. MmUnmapIoSpace(ReleaseAlias, 16);
  4346. return STATUS_SUCCESS;
  4347. }
  4348. #endif
  4349. NTSTATUS
  4350. RtpPatchHalSpinlockFunctions (
  4351. VOID
  4352. )
  4353. {
  4354. UNICODE_STRING AcquireLock;
  4355. UNICODE_STRING ReleaseLock;
  4356. PULONGLONG AcquireAddress, AcquireAlias;
  4357. PULONGLONG ReleaseAddress, ReleaseAlias;
  4358. PHYSICAL_ADDRESS AcquirePhysicalAddress;
  4359. PHYSICAL_ADDRESS ReleasePhysicalAddress;
  4360. // First get the virtual addresses of KfAcquireSpinLock and KfReleaseSpinLock.
  4361. RtlInitUnicodeString (&AcquireLock, (const PUSHORT)L"KfAcquireSpinLock");
  4362. RtlInitUnicodeString (&ReleaseLock, (const PUSHORT)L"KfReleaseSpinLock");
  4363. AcquireAddress=MmGetSystemRoutineAddress(&AcquireLock);
  4364. ReleaseAddress=MmGetSystemRoutineAddress(&ReleaseLock);
  4365. // Punt if we did not get both addresses.
  4366. if (!AcquireAddress || !ReleaseAddress) {
  4367. return STATUS_UNSUCCESSFUL;
  4368. }
  4369. // Make sure the code they point to starts like we expect it to. If not, punt.
  4370. OriginalAcquireCode=*AcquireAddress;
  4371. OriginalReleaseCode=*ReleaseAddress;
  4372. if ( ! ((OriginalAcquireCode==0xc6ffdff024a0c033 && OriginalReleaseCode==0xf0241588fa9cc933) || // UP HAL
  4373. (OriginalAcquireCode==0x05c7fffe0080158b && OriginalReleaseCode==0x888ac933c28ac033) || // APIC HAL
  4374. (OriginalAcquireCode==0xc6ffdff024a0c033 && OriginalReleaseCode==0xf0243d80cab60f9c)) // ACPI HAL
  4375. ) {
  4376. return STATUS_UNSUCCESSFUL;
  4377. }
  4378. #if 0
  4379. // Setup the release spinlock function we call for windows code. This makes sure that
  4380. // we run any additional code that the HAL normally runs after releasing a spinlock whenever
  4381. // a spinlock is released from a windows thread.
  4382. if (RtpSetupOriginalReleaseSpinlock(ReleaseAddress)!=STATUS_SUCCESS) {
  4383. return STATUS_UNSUCCESSFUL;
  4384. }
  4385. #endif
  4386. // Now alias the memory with our own writable pointer. So we can
  4387. // patch the code to jump to our routines.
  4388. AcquirePhysicalAddress=MmGetPhysicalAddress(AcquireAddress);
  4389. ReleasePhysicalAddress=MmGetPhysicalAddress(ReleaseAddress);
  4390. AcquireAlias=MmMapIoSpace(AcquirePhysicalAddress, 16, FALSE);
  4391. if (!AcquireAlias) {
  4392. return STATUS_UNSUCCESSFUL;
  4393. }
  4394. ReleaseAlias=MmMapIoSpace(ReleasePhysicalAddress, 16, FALSE);
  4395. if (!ReleaseAlias) {
  4396. MmUnmapIoSpace(AcquireAlias, 16);
  4397. return STATUS_UNSUCCESSFUL;
  4398. }
  4399. // Now patch the routines. Note that this code is not MP safe.
  4400. // Currently we will not be called except on uniprocessor machines.
  4401. SaveAndDisableMaskableInterrupts();
  4402. InterlockedCompareExchange64(AcquireAlias, *(PULONGLONG)PatchAcquire, OriginalAcquireCode);
  4403. InterlockedCompareExchange64(ReleaseAlias, *(PULONGLONG)PatchRelease, OriginalReleaseCode);
  4404. RestoreMaskableInterrupts();
  4405. // Release our alias mappings.
  4406. MmUnmapIoSpace(AcquireAlias, 16);
  4407. MmUnmapIoSpace(ReleaseAlias, 16);
  4408. return STATUS_SUCCESS;
  4409. }
  4410. #endif
  4411. VOID
  4412. MeasureRtTimeOverhead (
  4413. VOID
  4414. )
  4415. {
  4416. ULONGLONG Start, Finish, Temp;
  4417. ULONGLONG Original, Fast, Interlocked;
  4418. ULONG i;
  4419. Start=RtTime();
  4420. for (i=0; i<10000; i++) {
  4421. Temp=OriginalRtTime();
  4422. }
  4423. Finish=RtTime();
  4424. Original=Finish-Start;
  4425. Start=RtTime();
  4426. for (i=0; i<10000; i++) {
  4427. Temp=FastRtTime();
  4428. }
  4429. Finish=RtTime();
  4430. Fast=Finish-Start;
  4431. Start=RtTime();
  4432. for (i=0; i<10000; i++) {
  4433. Temp=RtTime();
  4434. }
  4435. Finish=RtTime();
  4436. Interlocked=Finish-Start;
  4437. DbgPrint("Original: %I64d, Fast: %I64d, Interlocked: %I64d\n", Original, Fast, Interlocked);
  4438. }
  4439. BOOL SetupRealTimeThreads(VOID)
  4440. {
  4441. //Break();
  4442. #ifdef UNDER_NT
  4443. // For now on NT we only support RT threads on non MP machines.
  4444. // We need to generalize the RT spinlock support to MP before we can run MP.
  4445. if (KeNumberProcessors>1) {
  4446. return FALSE;
  4447. }
  4448. #endif
  4449. if (!CPUManufacturer) {
  4450. if (!GetProcessorInfo()) {
  4451. return FALSE;
  4452. }
  4453. }
  4454. if (CPUManufacturer==AMD) {
  4455. // Since this is an AMD machine we need to update the performance counter
  4456. // model specific register locations. (They default to the Intel locations.)
  4457. // If we don't do this we will gp fault when we program the msrs.
  4458. PerformanceCounter0=AMDPERFORMANCECOUNTER0;
  4459. PerformanceCounter1=AMDPERFORMANCECOUNTER1;
  4460. EventSelect0=AMDEVENTSELECT0;
  4461. EventSelect1=AMDEVENTSELECT1;
  4462. PerformanceCounterMask=AMDPERFCOUNTMASK;
  4463. StopCounter=AMDSTOPPERFCOUNTER;
  4464. StartCycleCounter=AMDSTARTPERFCOUNTERS|AMDCOUNTCYCLES;
  4465. StartInstructionCounter=AMDSTARTPERFCOUNTERS|AMDCOUNTINSTRUCTIONS;
  4466. StartInterruptsDisabledCounter=AMDSTARTPERFCOUNTERS|AMDINTSDISABLEDWHILEPENDING;
  4467. }
  4468. if (CPUManufacturer==INTEL && CPUFamily==0xf) {
  4469. // This is Willamette processor. They changed things again...
  4470. PerformanceCounter0=WILLAMETTEPERFCOUNTER0;
  4471. PerformanceCounter1=WILLAMETTEPERFCOUNTER1;
  4472. EventSelect0=WILLAMETTECCR0;
  4473. EventSelect1=WILLAMETTECCR1;
  4474. StopCounter=WILLAMETTESTOPPERFCOUNTER;
  4475. StartCycleCounter=WILLAMETTESTARTPERFCOUNTERS|WILLAMETTECOUNTCYCLES;
  4476. StartInstructionCounter=WILLAMETTESTARTPERFCOUNTERS|WILLAMETTECOUNTINSTRUCTIONS;
  4477. }
  4478. if (!MachineHasAPIC()) {
  4479. return FALSE;
  4480. }
  4481. // Get a pointer to the system irql. We need this so we can properly
  4482. // maintain irql for realtime threads. If we don't get this, we don't
  4483. // run.
  4484. if (GetSystemIrqlPointer(&pCurrentIrql)!=STATUS_SUCCESS) {
  4485. Trap();
  4486. return FALSE;
  4487. }
  4488. if ( !NT_SUCCESS(InitializeRealTimeStack()) ) {
  4489. return FALSE;
  4490. }
  4491. if (!EnableAPIC()) {
  4492. return FALSE;
  4493. }
  4494. // If we got the local apic turned on, then we need to register with VPOWERD so
  4495. // that we can turn off the local apic before the machine shuts down or restarts.
  4496. // If we don't do that, then some broken Toshiba machines with mobile Celeron
  4497. // motherboards and bios will hang, since they have desktop Celerons in them.
  4498. // Mobile Celeron parts do not allow the apic to turn on. Desktop Celeron parts
  4499. // DO allow the local apic to turn on. It seems the mobile celeron bios gets
  4500. // confused if you restart the machine with the local apic in the desktop celeron
  4501. // turned on. So, to fix this we turn OFF the local apic on ALL machines before
  4502. // VPOWERD either shutsdown or restarts.
  4503. // Classic windows hack to fix stupid broken hardware.
  4504. #ifndef UNDER_NT
  4505. InitializeVPOWERD();
  4506. #endif
  4507. // First calibrate the cpu cycle counter.
  4508. if ( !NT_SUCCESS(RtpCalibrateCpuClock(&RtCpuCyclesPerUsec)) ) {
  4509. Trap();
  4510. return FALSE;
  4511. }
  4512. if ( RtCpuCyclesPerUsec<160 ) {
  4513. Trap();
  4514. return FALSE;
  4515. }
  4516. RtPsecPerCpuCycle=USEC/RtCpuCyclesPerUsec;
  4517. // Now calibrate the local apic timer - which is clocked from the system bus.
  4518. if ( !NT_SUCCESS(RtpCalibrateSystemBus(RtCpuCyclesPerUsec, &RtSystemBusCyclesPerUsec)) ) {
  4519. Trap();
  4520. return FALSE;
  4521. }
  4522. if (RtSystemBusCyclesPerUsec<57) { // Some PPro's have ~60MHz buses.
  4523. Trap();
  4524. return FALSE;
  4525. }
  4526. if ( !NT_SUCCESS(RtpEnableApicTimer()) ) {
  4527. return FALSE;
  4528. }
  4529. RtpSetupStreamingSIMD();
  4530. RtpSetupIdtSwitch(ApicTimerVector, ApicPerfVector, ApicErrorVector, ApicSpuriousVector);
  4531. if ( !NT_SUCCESS(RtpInitializeThreadList()) ) {
  4532. return FALSE;
  4533. }
  4534. HookWindowsInterrupts(ApicTimerVector, ApicErrorVector);
  4535. SetupPerformanceCounters();
  4536. SetTimeLimit( 0, 0);
  4537. #ifndef UNDER_NT
  4538. if (!NT_SUCCESS(RtpSetupPowerManagement())) {
  4539. return FALSE;
  4540. }
  4541. // Don't tell NTKERN we are here until we KNOW everything is set to go.
  4542. // Once we make this call the KeAcquireSpinLock and KeReleaseSpinLock
  4543. // calls will assume that rt support is on and running.
  4544. InitializeNT();
  4545. #endif
  4546. #ifdef UNDER_NT
  4547. if (RtpPatchHalSpinlockFunctions()!=STATUS_SUCCESS) {
  4548. return FALSE;
  4549. }
  4550. #endif
  4551. #ifdef MASKABLEINTERRUPT
  4552. // Snap the dynalink to KfLowerIrql.
  4553. WrapKfLowerIrql(KeGetCurrentIrql());
  4554. #endif
  4555. // At this point, everything is ready to roll. Before we enable our APIs,
  4556. // we first run some calibration code to determine the overhead involved in
  4557. // switching threads.
  4558. //MeasureRealTimeExecutiveOverhead();
  4559. // One run of the below measurements gave the following output.
  4560. // Original: 7295923440, Fast: 2771265627, Interlocked: 5724782154
  4561. //MeasureRtTimeOverhead();
  4562. // Now set our loaded flag so that the external RT APIs succeed.
  4563. RtRunning=1;
  4564. //RtCreateThread(3500*MSEC, 3500*USEC, 0, 2, thread1, NULL, NULL);
  4565. //RtCreateThread(thread2,2,0);
  4566. //RtCreateThread(1*MSEC, 0, 0, 1, thread3, NULL, NULL);
  4567. //RtCreateThread(1*MSEC, 10*USEC, 0, 1, thread4, NULL, NULL);
  4568. //RtCreateThread(1*MSEC, 10*USEC, USESFLOAT|USESMMX, 1, thread5, NULL, NULL);
  4569. //RtCreateThread(10*MSEC, 1000*USEC, USESFLOAT|USESMMX, 1, thread6, NULL, NULL);
  4570. //RtCreateThread(20*MSEC, 2000*USEC, 0, 1, thread6, NULL, NULL);
  4571. #ifdef CATCH_INTERRUPTS_DISABLED_TOO_LONG
  4572. RtCreateThread(1*MSEC, 3*USEC, 0, 1, ResetInterruptsDisabledCounter, NULL, NULL);
  4573. #endif
  4574. return TRUE;
  4575. }