timer.c 52 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280
  1. /*++
  2. Copyright (c) 2012 Minoca Corp. All Rights Reserved
  3. Module Name:
  4. timer.c
  5. Abstract:
  6. This module implements timer support for the hardware library.
  7. Author:
  8. Evan Green 28-Oct-2012
  9. Environment:
  10. Kernel
  11. --*/
  12. //
  13. // ------------------------------------------------------------------- Includes
  14. //
  15. #include <minoca/kernel/kernel.h>
  16. #include <minoca/kernel/bootload.h>
  17. #include "hlp.h"
  18. #include "calendar.h"
  19. #include "intrupt.h"
  20. #include "timer.h"
  21. #include "clock.h"
  22. #include "profiler.h"
  23. //
  24. // ---------------------------------------------------------------- Definitions
  25. //
  26. //
  27. // Store the amount of time, in microseconds, that the refernce stall should
  28. // take.
  29. //
  30. #define REFERENCE_STALL_DURATION 250000
  31. //
  32. // Find timer options.
  33. //
  34. #define FIND_TIMER_OPTION_INCLUDE_USED_FOR_INTERRUPT_ANY 0x00000001
  35. #define FIND_TIMER_OPTION_INCLUDE_USED_FOR_COUNTER 0x00000002
  36. #define FIND_TIMER_OPTION_INCLUDE_USED_FOR_INTERRUPT_ABSOLUTE 0x00000004
  37. //
  38. // ------------------------------------------------------ Data Type Definitions
  39. //
  40. //
  41. // ----------------------------------------------- Internal Function Prototypes
  42. //
  43. KSTATUS
  44. HlpTimerInitialize (
  45. PHARDWARE_TIMER Timer
  46. );
  47. KSTATUS
  48. HlpTimerMeasureUnknownFrequencies (
  49. VOID
  50. );
  51. PHARDWARE_TIMER
  52. HlpTimerFindIdealMeasuringSource (
  53. VOID
  54. );
  55. PHARDWARE_TIMER
  56. HlpTimerFindIdealClockSource (
  57. VOID
  58. );
  59. PHARDWARE_TIMER
  60. HlpTimerFindIdealProfilerSource (
  61. VOID
  62. );
  63. PHARDWARE_TIMER
  64. HlpTimerFindIdealTimeCounter (
  65. VOID
  66. );
  67. PHARDWARE_TIMER
  68. HlpTimerFindIdealProcessorCounter (
  69. VOID
  70. );
  71. PHARDWARE_TIMER
  72. HlpTimerFind (
  73. ULONG RequiredFeatures,
  74. ULONG RequiredNonFeatures,
  75. ULONG FindOptions
  76. );
  77. VOID
  78. HlpTimerBusyStall (
  79. PHARDWARE_TIMER Timer,
  80. ULONG Microseconds
  81. );
  82. KSTATUS
  83. HlpTimerAssignRoles (
  84. VOID
  85. );
  86. VOID
  87. HlpTimerResetCounterOffset (
  88. PHARDWARE_TIMER Timer,
  89. ULONGLONG NewValue
  90. );
  91. KSTATUS
  92. HlpTimerCreateSoftUpdateTimer (
  93. PHARDWARE_TIMER Timer
  94. );
  95. //
  96. // -------------------------------------------------------------------- Globals
  97. //
  98. //
  99. // Store the list of timers.
  100. //
  101. LIST_ENTRY HlTimers;
  102. //
  103. // Store pointers to the timers backing system services.
  104. //
  105. PHARDWARE_TIMER HlClockTimer;
  106. PHARDWARE_TIMER HlProfilerTimer;
  107. PHARDWARE_TIMER HlTimeCounter;
  108. PHARDWARE_TIMER HlProcessorCounter;
  109. //
  110. // If KD stalls are temporarily disabled, remember the original value so they
  111. // can be re-enabled when a stall source is brought online.
  112. //
  113. ULONG HlOriginalKdConnectionTimeout;
  114. //
  115. // ------------------------------------------------------------------ Functions
  116. //
  117. KERNEL_API
  118. ULONGLONG
  119. HlQueryTimeCounter (
  120. VOID
  121. )
  122. /*++
  123. Routine Description:
  124. This routine queries the time counter hardware and returns a 64-bit
  125. monotonically non-decreasing value that represents the number of timer ticks
  126. since the system was started. This value will continue to count through all
  127. idle and sleep states.
  128. This routine can be called at any runlevel.
  129. Arguments:
  130. None.
  131. Return Value:
  132. Returns the number of timer ticks that have elapsed since the system was
  133. booted. The absolute time between successive ticks can be retrieved from the
  134. Query Time Counter Frequency function.
  135. --*/
  136. {
  137. return HlpTimerExtendedQuery(HlTimeCounter);
  138. }
  139. KERNEL_API
  140. ULONGLONG
  141. HlQueryTimeCounterFrequency (
  142. VOID
  143. )
  144. /*++
  145. Routine Description:
  146. This routine returns the frequency of the time counter. This frequency will
  147. never change after it is set on boot.
  148. This routine can be called at any runlevel.
  149. Arguments:
  150. None.
  151. Return Value:
  152. Returns the frequency of the time counter, in Hertz.
  153. --*/
  154. {
  155. if (HlTimeCounter == NULL) {
  156. return 0;
  157. }
  158. return HlTimeCounter->CounterFrequency;
  159. }
  160. KERNEL_API
  161. ULONGLONG
  162. HlQueryProcessorCounterFrequency (
  163. VOID
  164. )
  165. /*++
  166. Routine Description:
  167. This routine returns the frequency of the processor counter. This frequency
  168. will never change after it is set on boot.
  169. This routine can be called at any runlevel.
  170. Arguments:
  171. None.
  172. Return Value:
  173. Returns the frequency of the time counter, in Hertz.
  174. --*/
  175. {
  176. if (HlProcessorCounter == NULL) {
  177. return 0;
  178. }
  179. return HlProcessorCounter->CounterFrequency;
  180. }
  181. KERNEL_API
  182. VOID
  183. HlBusySpin (
  184. ULONG Microseconds
  185. )
  186. /*++
  187. Routine Description:
  188. This routine spins for at least the given number of microseconds by
  189. repeatedly reading a hardware timer. This routine should be avoided if at
  190. all possible, as it simply burns CPU cycles.
  191. This routine can be called at any runlevel.
  192. Arguments:
  193. Microseconds - Supplies the number of microseconds to spin for.
  194. Return Value:
  195. Returns the frequency of the time counter, in Hertz.
  196. --*/
  197. {
  198. HlpTimerBusyStall(HlTimeCounter, Microseconds);
  199. return;
  200. }
  201. KSTATUS
  202. HlpInitializeTimersPreDebugger (
  203. PKERNEL_INITIALIZATION_BLOCK Parameters,
  204. ULONG ProcessorNumber
  205. )
  206. /*++
  207. Routine Description:
  208. This routine implements early timer initialization for the hardware module
  209. API layer. This routine is *undebuggable*, as it is called before the
  210. debugger is brought online.
  211. Arguments:
  212. Parameters - Supplies an optional pointer to the kernel initialization
  213. parameters. This parameter may be NULL.
  214. ProcessorNumber - Supplies the processor index of this processor.
  215. Return Value:
  216. None.
  217. --*/
  218. {
  219. PLIST_ENTRY CurrentEntry;
  220. KSTATUS Status;
  221. PHARDWARE_TIMER Timer;
  222. if ((ProcessorNumber != 0) || (Parameters == NULL)) {
  223. return STATUS_SUCCESS;
  224. }
  225. INITIALIZE_LIST_HEAD(&HlTimers);
  226. HlpArchInitializeTimersPreDebugger();
  227. //
  228. // Attempt to find and initialize the processor counter.
  229. //
  230. CurrentEntry = HlTimers.Next;
  231. while (CurrentEntry != &HlTimers) {
  232. Timer = LIST_VALUE(CurrentEntry, HARDWARE_TIMER, ListEntry);
  233. CurrentEntry = CurrentEntry->Next;
  234. if ((Timer->Features & TIMER_FEATURE_PROCESSOR_COUNTER) != 0) {
  235. if (Timer->CounterFrequency == 0) {
  236. Timer->CounterFrequency = Parameters->CycleCounterFrequency;
  237. }
  238. }
  239. if (Timer->CounterFrequency != 0) {
  240. Status = HlpTimerInitialize(Timer);
  241. if (KSUCCESS(Status)) {
  242. if ((Timer->Features & TIMER_FEATURE_READABLE) != 0) {
  243. HlProcessorCounter = Timer;
  244. HlTimeCounter = Timer;
  245. }
  246. }
  247. }
  248. }
  249. //
  250. // If no stall source was set up, then inhibit the debugger from using it.
  251. //
  252. if (HlTimeCounter == NULL) {
  253. HlOriginalKdConnectionTimeout = KdSetConnectionTimeout(MAX_ULONG);
  254. }
  255. return STATUS_SUCCESS;
  256. }
  257. KSTATUS
  258. HlpInitializeTimers (
  259. PKERNEL_INITIALIZATION_BLOCK Parameters
  260. )
  261. /*++
  262. Routine Description:
  263. This routine initializes the timer subsystem.
  264. Arguments:
  265. Parameters - Supplies a pointer to the kernel's initialization information.
  266. Return Value:
  267. Status code.
  268. --*/
  269. {
  270. UINTN AllocationSize;
  271. PULONGLONG CountArray;
  272. PLIST_ENTRY CurrentEntry;
  273. ULONG ProcessorCount;
  274. BOOL RestoreKd;
  275. KSTATUS Status;
  276. PHARDWARE_TIMER Timer;
  277. if (KeGetCurrentProcessorNumber() == 0) {
  278. INITIALIZE_LIST_HEAD(&HlCalendarTimers);
  279. //
  280. // If no time counter was able to be set up during early
  281. // initialization, then KD stalls were disabled. Mark now to restore
  282. // them.
  283. //
  284. RestoreKd = FALSE;
  285. if (HlTimeCounter == NULL) {
  286. RestoreKd = TRUE;
  287. }
  288. //
  289. // Loop through any timers that were created super early and allocate
  290. // per-processor arrays for them if necessary.
  291. //
  292. ProcessorCount = HlGetMaximumProcessorCount();
  293. ASSERT(ProcessorCount != 0);
  294. CurrentEntry = HlTimers.Next;
  295. while (CurrentEntry != &HlTimers) {
  296. Timer = LIST_VALUE(CurrentEntry, HARDWARE_TIMER, ListEntry);
  297. CurrentEntry = CurrentEntry->Next;
  298. if ((Timer->CounterBitWidth < 64) &&
  299. ((Timer->Features & TIMER_FEATURE_VARIANT) != 0) &&
  300. ((Timer->Features & TIMER_FEATURE_PER_PROCESSOR) != 0)) {
  301. AllocationSize = ProcessorCount * sizeof(ULONGLONG);
  302. CountArray = HlAllocateMemory(AllocationSize,
  303. HL_POOL_TAG,
  304. FALSE,
  305. NULL);
  306. if (CountArray == NULL) {
  307. Status = STATUS_INSUFFICIENT_RESOURCES;
  308. goto InitializeTimersEnd;
  309. }
  310. RtlZeroMemory(CountArray, AllocationSize);
  311. CountArray[0] = Timer->CurrentCount;
  312. Timer->CurrentCounts = CountArray;
  313. }
  314. }
  315. //
  316. // Perform architecture-specific initialization.
  317. //
  318. Status = HlpArchInitializeTimers();
  319. if (!KSUCCESS(Status)) {
  320. goto InitializeTimersEnd;
  321. }
  322. //
  323. // Measure the frequencies of any unknown timers.
  324. //
  325. Status = HlpTimerMeasureUnknownFrequencies();
  326. if (!KSUCCESS(Status)) {
  327. goto InitializeTimersEnd;
  328. }
  329. //
  330. // Assign timers to system services.
  331. //
  332. Status = HlpTimerAssignRoles();
  333. if (!KSUCCESS(Status)) {
  334. goto InitializeTimersEnd;
  335. }
  336. //
  337. // Set t = 0 for the time counter.
  338. //
  339. HlpTimerResetCounterOffset(HlTimeCounter, 0);
  340. //
  341. // Restore the original KD connection timeout if it was disabled.
  342. //
  343. if (RestoreKd != FALSE) {
  344. KdSetConnectionTimeout(HlOriginalKdConnectionTimeout);
  345. }
  346. //
  347. // Fire up the clock.
  348. //
  349. Status = HlpTimerInitializeClock();
  350. if (!KSUCCESS(Status)) {
  351. goto InitializeTimersEnd;
  352. }
  353. //
  354. // Initialize the profiler.
  355. //
  356. Status = HlpTimerInitializeProfiler();
  357. if (!KSUCCESS(Status)) {
  358. goto InitializeTimersEnd;
  359. }
  360. //
  361. // Initialize the clock for polling the debugger now that the final
  362. // time counter source has been set up.
  363. //
  364. KeUpdateClockForProfiling(FALSE);
  365. //
  366. // Create a soft timer to ensure that the system wakes from idle at
  367. // least often enough to observe every half-rollover of the time
  368. // counter.
  369. //
  370. Status = HlpTimerCreateSoftUpdateTimer(HlTimeCounter);
  371. if (!KSUCCESS(Status)) {
  372. goto InitializeTimersEnd;
  373. }
  374. //
  375. // Perform initialization for all other processors.
  376. //
  377. } else {
  378. CurrentEntry = HlTimers.Next;
  379. while (CurrentEntry != &HlTimers) {
  380. Timer = LIST_VALUE(CurrentEntry, HARDWARE_TIMER, ListEntry);
  381. CurrentEntry = CurrentEntry->Next;
  382. if (((Timer->Features & TIMER_FEATURE_PER_PROCESSOR) != 0) &&
  383. ((Timer->Flags & TIMER_FLAG_INITIALIZED) != 0)) {
  384. //
  385. // Initialize the timer on this new processor. If the timer
  386. // fails and it's backing a system service, this is a problem.
  387. //
  388. Status = HlpTimerInitialize(Timer);
  389. if (!KSUCCESS(Status)) {
  390. goto InitializeTimersEnd;
  391. }
  392. }
  393. }
  394. //
  395. // Fire up the clock.
  396. //
  397. Status = HlpTimerInitializeClock();
  398. if (!KSUCCESS(Status)) {
  399. goto InitializeTimersEnd;
  400. }
  401. //
  402. // Finish profiler initialization.
  403. //
  404. Status = HlpTimerInitializeProfiler();
  405. if (!KSUCCESS(Status)) {
  406. goto InitializeTimersEnd;
  407. }
  408. }
  409. InitializeTimersEnd:
  410. return Status;
  411. }
  412. KSTATUS
  413. HlpTimerRegisterHardware (
  414. PTIMER_DESCRIPTION TimerDescription
  415. )
  416. /*++
  417. Routine Description:
  418. This routine is called to register a new timer with the system.
  419. Arguments:
  420. TimerDescription - Supplies a pointer to a structure describing the new
  421. timer.
  422. Return Value:
  423. Status code.
  424. --*/
  425. {
  426. UINTN AbsoluteArrayOffset;
  427. UINTN AllocationSize;
  428. ULONG ArmFlags;
  429. UINTN CounterArrayOffset;
  430. ULONG DisarmFlags;
  431. ULONG InterruptFlags;
  432. ULONG ProcessorCount;
  433. KSTATUS Status;
  434. PHARDWARE_TIMER Timer;
  435. Timer = NULL;
  436. //
  437. // Check the table version.
  438. //
  439. if (TimerDescription->TableVersion < TIMER_DESCRIPTION_VERSION) {
  440. Status = STATUS_INVALID_PARAMETER;
  441. goto TimerRegisterHardwareEnd;
  442. }
  443. //
  444. // Check required function pointers.
  445. //
  446. if (TimerDescription->FunctionTable.Initialize == NULL) {
  447. Status = STATUS_INVALID_PARAMETER;
  448. goto TimerRegisterHardwareEnd;
  449. }
  450. //
  451. // Non-periodic, absolute timers must be readable and per-processor.
  452. //
  453. if (((TimerDescription->Features & TIMER_FEATURE_ABSOLUTE) != 0) &&
  454. ((TimerDescription->Features & TIMER_FEATURE_PERIODIC) == 0)) {
  455. if ((TimerDescription->Features & TIMER_FEATURE_READABLE) == 0) {
  456. Status = STATUS_INVALID_PARAMETER;
  457. goto TimerRegisterHardwareEnd;
  458. }
  459. //
  460. // The requirement that non-periodic absolute timers must be
  461. // per-processor stems from the difficulty of synchronizing rearming
  462. // the timer during acknowledge interrupt. Handling races between one
  463. // core arming the timer and another core acknowledging the timer's
  464. // interrupt adds complexity that is not yet worth including.
  465. //
  466. if ((TimerDescription->Features & TIMER_FEATURE_PER_PROCESSOR) == 0) {
  467. Status = STATUS_INVALID_PARAMETER;
  468. goto TimerRegisterHardwareEnd;
  469. }
  470. }
  471. //
  472. // If the readable feature is set then the read counter routine is required.
  473. //
  474. if (((TimerDescription->Features & TIMER_FEATURE_READABLE) != 0) &&
  475. (TimerDescription->FunctionTable.ReadCounter == NULL)) {
  476. Status = STATUS_INVALID_PARAMETER;
  477. goto TimerRegisterHardwareEnd;
  478. }
  479. //
  480. // If the writable feature is set then the write counter routine is
  481. // required.
  482. //
  483. if (((TimerDescription->Features & TIMER_FEATURE_WRITABLE) != 0) &&
  484. (TimerDescription->FunctionTable.WriteCounter == NULL)) {
  485. Status = STATUS_INVALID_PARAMETER;
  486. goto TimerRegisterHardwareEnd;
  487. }
  488. //
  489. // If the one-shot, periodic or absolute deadline features are set then the
  490. // arm timer routine is required.
  491. //
  492. ArmFlags = TIMER_FEATURE_ONE_SHOT |
  493. TIMER_FEATURE_PERIODIC |
  494. TIMER_FEATURE_ABSOLUTE;
  495. if (((TimerDescription->Features & ArmFlags) != 0) &&
  496. (TimerDescription->FunctionTable.Arm == NULL)) {
  497. Status = STATUS_INVALID_PARAMETER;
  498. goto TimerRegisterHardwareEnd;
  499. }
  500. //
  501. // If the periodic or absolute deadline features are set then the disarm
  502. // timer routine is required.
  503. //
  504. DisarmFlags = TIMER_FEATURE_PERIODIC | TIMER_FEATURE_ABSOLUTE;
  505. if (((TimerDescription->Features & DisarmFlags) != 0) &&
  506. (TimerDescription->FunctionTable.Disarm == NULL)) {
  507. Status = STATUS_INVALID_PARAMETER;
  508. goto TimerRegisterHardwareEnd;
  509. }
  510. //
  511. // The counter bit width had better not be zero.
  512. //
  513. if (TimerDescription->CounterBitWidth < 2) {
  514. Status = STATUS_INVALID_PARAMETER;
  515. goto TimerRegisterHardwareEnd;
  516. }
  517. //
  518. // If the timer generates interrupts, it had better have properly described
  519. // its interrupt.
  520. //
  521. InterruptFlags = TIMER_FEATURE_ONE_SHOT |
  522. TIMER_FEATURE_PERIODIC |
  523. TIMER_FEATURE_ABSOLUTE;
  524. if (((TimerDescription->Features & InterruptFlags) != 0) &&
  525. (TimerDescription->Interrupt.Line.Type == InterruptLineInvalid)) {
  526. Status = STATUS_INVALID_PARAMETER;
  527. goto TimerRegisterHardwareEnd;
  528. }
  529. //
  530. // Allocate the new controller object. If the timer varies per processor
  531. // then the current count array needs to be kept per processor. If this is
  532. // very early initialization (pre-debugger), then the processor count might
  533. // return zero, in which case don't allocate the per-processor array yet.
  534. // That will be created later.
  535. //
  536. CounterArrayOffset = 0;
  537. AllocationSize = sizeof(HARDWARE_TIMER);
  538. if ((TimerDescription->CounterBitWidth < 64) &&
  539. ((TimerDescription->Features & TIMER_FEATURE_VARIANT) != 0) &&
  540. ((TimerDescription->Features & TIMER_FEATURE_PER_PROCESSOR) != 0)) {
  541. ProcessorCount = HlGetMaximumProcessorCount();
  542. if (ProcessorCount > 1) {
  543. //
  544. // Align the allocation size so that the array of 64-bit integers is
  545. // aligned to 64-bits, which is required for doing atomic access on
  546. // some architectures.
  547. //
  548. AllocationSize = ALIGN_RANGE_UP(AllocationSize, sizeof(ULONGLONG));
  549. CounterArrayOffset = AllocationSize;
  550. AllocationSize += ProcessorCount * sizeof(ULONGLONG);
  551. }
  552. }
  553. //
  554. // Non-periodic, absolute timers require extra data in order to fake
  555. // periodic support.
  556. //
  557. AbsoluteArrayOffset = 0;
  558. if (((TimerDescription->Features & TIMER_FEATURE_ABSOLUTE) != 0) &&
  559. ((TimerDescription->Features & TIMER_FEATURE_PERIODIC) == 0)) {
  560. ASSERT((TimerDescription->Features & TIMER_FEATURE_PER_PROCESSOR) != 0);
  561. ProcessorCount = HlGetMaximumProcessorCount();
  562. ASSERT(ProcessorCount != 0);
  563. AllocationSize = ALIGN_RANGE_UP(AllocationSize, sizeof(ULONGLONG));
  564. AbsoluteArrayOffset = AllocationSize;
  565. AllocationSize += ProcessorCount * sizeof(HARDWARE_TIMER_ABSOLUTE_DATA);
  566. }
  567. Timer = HlAllocateMemory(AllocationSize, HL_POOL_TAG, FALSE, NULL);
  568. if (Timer == NULL) {
  569. Status = STATUS_INSUFFICIENT_RESOURCES;
  570. goto TimerRegisterHardwareEnd;
  571. }
  572. RtlZeroMemory(Timer, AllocationSize);
  573. //
  574. // Initialize the new timer based on the description.
  575. //
  576. RtlCopyMemory(&(Timer->FunctionTable),
  577. &(TimerDescription->FunctionTable),
  578. sizeof(TIMER_FUNCTION_TABLE));
  579. Timer->Identifier = TimerDescription->Identifier;
  580. Timer->PrivateContext = TimerDescription->Context;
  581. Timer->Features = TimerDescription->Features;
  582. Timer->CounterBitWidth = TimerDescription->CounterBitWidth;
  583. Timer->CounterFrequency = TimerDescription->CounterFrequency;
  584. Timer->Flags = 0;
  585. Timer->Interrupt = TimerDescription->Interrupt;
  586. Timer->InterruptRunLevel = RunLevelCount;
  587. if (CounterArrayOffset != 0) {
  588. Timer->CurrentCounts = (PVOID)Timer + CounterArrayOffset;
  589. }
  590. if (AbsoluteArrayOffset != 0) {
  591. Timer->AbsoluteData = (PVOID)Timer + AbsoluteArrayOffset;
  592. }
  593. //
  594. // Insert the timer on the list.
  595. //
  596. INSERT_BEFORE(&(Timer->ListEntry), &HlTimers);
  597. Status = STATUS_SUCCESS;
  598. TimerRegisterHardwareEnd:
  599. return Status;
  600. }
  601. KSTATUS
  602. HlpTimerArm (
  603. PHARDWARE_TIMER Timer,
  604. TIMER_MODE Mode,
  605. ULONGLONG TickCount
  606. )
  607. /*++
  608. Routine Description:
  609. This routine arms a timer to fire an interrupt after the given interval.
  610. Arguments:
  611. Timer - Supplies a pointer to the timer to arm.
  612. Mode - Supplies whether or not this should be a recurring timer or not.
  613. TickCount - Supplies the number of timer ticks from now for the timer to
  614. fire in. In absolute mode, this supplies the time in timer ticks at
  615. which to fire an interrupt.
  616. Return Value:
  617. STATUS_SUCCESS on success.
  618. STATUS_NOT_SUPPORTED if the timer cannot support the requested mode.
  619. Other status codes on failure.
  620. --*/
  621. {
  622. PHARDWARE_TIMER_ABSOLUTE_DATA AbsoluteData;
  623. ULONG AbsoluteIndex;
  624. ULONGLONG CurrentTime;
  625. ULONGLONG DueTime;
  626. ULONGLONG HalfRolloverTicks;
  627. RUNLEVEL OldRunLevel;
  628. PVOID PrivateContext;
  629. KSTATUS Status;
  630. //
  631. // Non-periodic, absolute timers require a little extra massaging in order
  632. // to support periodic requests - they need to be converted to absolute
  633. // requests.
  634. //
  635. OldRunLevel = RunLevelCount;
  636. if (((Timer->Features & TIMER_FEATURE_ABSOLUTE) != 0) &&
  637. ((Timer->Features & TIMER_FEATURE_PERIODIC) == 0)) {
  638. ASSERT((Timer->Features & TIMER_FEATURE_PER_PROCESSOR) != 0);
  639. ASSERT(Timer->InterruptRunLevel != RunLevelCount);
  640. //
  641. // Raise to the interrupt's run level in order to synchronize rearming
  642. // the timer during acknowledge interrupt with this new call to arm the
  643. // timer.
  644. //
  645. AbsoluteIndex = KeGetCurrentProcessorNumber();
  646. AbsoluteData = &(Timer->AbsoluteData[AbsoluteIndex]);
  647. OldRunLevel = KeRaiseRunLevel(Timer->InterruptRunLevel);
  648. switch (Mode) {
  649. //
  650. // Periodic mode is faked for non-periodic absolute timers, by having
  651. // acknowledge interrupt rearm the timer. Convert the tick count to an
  652. // absolute deadline and save the period so that the timer can be
  653. // rearmed during interrupt handling.
  654. //
  655. case TimerModePeriodic:
  656. //
  657. // Make sure the tick count is less than half the rollover rate.
  658. // Absolute timers need to be able to differentiate between a time
  659. // shortly in the past and a time in the far future.
  660. //
  661. HalfRolloverTicks = 1ULL << (Timer->CounterBitWidth - 1);
  662. if (TickCount > HalfRolloverTicks) {
  663. TickCount = HalfRolloverTicks;
  664. }
  665. //
  666. // Calculate the absolute due time, only sending the hardware bits
  667. // it knows about.
  668. //
  669. PrivateContext = Timer->PrivateContext;
  670. CurrentTime = Timer->FunctionTable.ReadCounter(PrivateContext);
  671. DueTime = CurrentTime + TickCount;
  672. DueTime &= (1ULL << Timer->CounterBitWidth) - 1;
  673. //
  674. // Save the periodic state so acknowledge interrupt can rearm the
  675. // timer.
  676. //
  677. AbsoluteData->Period = TickCount;
  678. AbsoluteData->DueTime = DueTime;
  679. //
  680. // Convert from periodic mode to absolute mode.
  681. //
  682. TickCount = DueTime;
  683. Mode = TimerModeAbsolute;
  684. break;
  685. //
  686. // For both one-shot and absolute modes, set the period to 0 so that
  687. // acknowledge interrupt does not rearm the timer.
  688. //
  689. case TimerModeOneShot:
  690. if ((Timer->Features & TIMER_FEATURE_ONE_SHOT) == 0) {
  691. Status = STATUS_NOT_SUPPORTED;
  692. goto TimerArmEnd;
  693. }
  694. //
  695. // Fall through.
  696. //
  697. case TimerModeAbsolute:
  698. AbsoluteData->Period = 0;
  699. break;
  700. default:
  701. Status = STATUS_INVALID_PARAMETER;
  702. goto TimerArmEnd;
  703. }
  704. //
  705. // Otherwise, all periodic requests take relative tick counts and there is
  706. // no extra work to do.
  707. //
  708. } else {
  709. switch (Mode) {
  710. case TimerModePeriodic:
  711. if ((Timer->Features & TIMER_FEATURE_PERIODIC) == 0) {
  712. Status = STATUS_NOT_SUPPORTED;
  713. goto TimerArmEnd;
  714. }
  715. break;
  716. case TimerModeOneShot:
  717. if ((Timer->Features & TIMER_FEATURE_ONE_SHOT) == 0) {
  718. Status = STATUS_NOT_SUPPORTED;
  719. goto TimerArmEnd;
  720. }
  721. break;
  722. case TimerModeAbsolute:
  723. if ((Timer->Features & TIMER_FEATURE_ABSOLUTE) == 0) {
  724. Status = STATUS_NOT_SUPPORTED;
  725. goto TimerArmEnd;
  726. }
  727. break;
  728. default:
  729. Status = STATUS_INVALID_PARAMETER;
  730. goto TimerArmEnd;
  731. }
  732. }
  733. //
  734. // Arm the timer to begin counting.
  735. //
  736. Status = Timer->FunctionTable.Arm(Timer->PrivateContext, Mode, TickCount);
  737. if (!KSUCCESS(Status)) {
  738. goto TimerArmEnd;
  739. }
  740. TimerArmEnd:
  741. ASSERT(KSUCCESS(Status));
  742. if (OldRunLevel != RunLevelCount) {
  743. KeLowerRunLevel(OldRunLevel);
  744. }
  745. return Status;
  746. }
  747. VOID
  748. HlpTimerDisarm (
  749. PHARDWARE_TIMER Timer
  750. )
  751. /*++
  752. Routine Description:
  753. This routine disarms a timer, stopping it from firing interrupts.
  754. Arguments:
  755. Timer - Supplies a pointer to the timer to disarm.
  756. Return Value:
  757. None.
  758. --*/
  759. {
  760. PHARDWARE_TIMER_ABSOLUTE_DATA AbsoluteData;
  761. ULONG AbsoluteIndex;
  762. RUNLEVEL OldRunLevel;
  763. ASSERT(Timer != NULL);
  764. //
  765. // If this is a non-periodic absolute timer, raise to the interrupt's run
  766. // level and set the period to 0 so that acknowledge interrupt does not
  767. // rearm the timer.
  768. //
  769. OldRunLevel = RunLevelCount;
  770. if (((Timer->Features & TIMER_FEATURE_ABSOLUTE) != 0) &&
  771. ((Timer->Features & TIMER_FEATURE_PERIODIC) == 0)) {
  772. ASSERT((Timer->Features & TIMER_FEATURE_PER_PROCESSOR) != 0);
  773. ASSERT(Timer->InterruptRunLevel != RunLevelCount);
  774. AbsoluteIndex = KeGetCurrentProcessorNumber();
  775. AbsoluteData = &(Timer->AbsoluteData[AbsoluteIndex]);
  776. OldRunLevel = KeRaiseRunLevel(Timer->InterruptRunLevel);
  777. AbsoluteData->Period = 0;
  778. }
  779. //
  780. // Disarm the timer.
  781. //
  782. Timer->FunctionTable.Disarm(Timer->PrivateContext);
  783. if (OldRunLevel != RunLevelCount) {
  784. KeLowerRunLevel(OldRunLevel);
  785. }
  786. return;
  787. }
  788. VOID
  789. HlpTimerAcknowledgeInterrupt (
  790. PHARDWARE_TIMER Timer
  791. )
  792. /*++
  793. Routine Description:
  794. This routine acknowledges a timer interrupt. If the timer is a non-periodic
  795. absolute timer, this will rearm the timer if it is still in periodic mode.
  796. Arguments:
  797. Timer - Supplies a pointer to the timer whose interrupt is to be
  798. acknowledged.
  799. Return Value:
  800. None.
  801. --*/
  802. {
  803. PHARDWARE_TIMER_ABSOLUTE_DATA AbsoluteData;
  804. ULONG AbsoluteIndex;
  805. PTIMER_ACKNOWLEDGE_INTERRUPT AcknowledgeInterrupt;
  806. PVOID Context;
  807. ULONGLONG CurrentTime;
  808. ULONGLONG DueTime;
  809. ULONGLONG ExtendedCurrentTime;
  810. ULONGLONG ExtendedDueTime;
  811. ULONGLONG Period;
  812. AcknowledgeInterrupt = Timer->FunctionTable.AcknowledgeInterrupt;
  813. if (AcknowledgeInterrupt != NULL) {
  814. AcknowledgeInterrupt(Timer->PrivateContext);
  815. }
  816. //
  817. // If it's a non-periodic absolute timer, then attempt to rearm it.
  818. //
  819. if (((Timer->Features & TIMER_FEATURE_ABSOLUTE) != 0) &&
  820. ((Timer->Features & TIMER_FEATURE_PERIODIC) == 0)) {
  821. ASSERT((Timer->Features & TIMER_FEATURE_PER_PROCESSOR) != 0);
  822. ASSERT(KeGetRunLevel() == Timer->InterruptRunLevel);
  823. AbsoluteIndex = KeGetCurrentProcessorNumber();
  824. AbsoluteData = &(Timer->AbsoluteData[AbsoluteIndex]);
  825. Period = AbsoluteData->Period;
  826. if (Period != 0) {
  827. Context = Timer->PrivateContext;
  828. DueTime = AbsoluteData->DueTime + Period;
  829. DueTime &= (1ULL << Timer->CounterBitWidth) - 1;
  830. CurrentTime = Timer->FunctionTable.ReadCounter(Context);
  831. //
  832. // If the current time is already ahead of the calculated due time,
  833. // then this timer got behind (likely due to a debug break). Catch
  834. // it up by programming a time in the future.
  835. //
  836. ExtendedDueTime = DueTime << (64 - Timer->CounterBitWidth);
  837. ExtendedCurrentTime = CurrentTime << (64 - Timer->CounterBitWidth);
  838. if ((LONGLONG)(ExtendedDueTime - ExtendedCurrentTime) < 0) {
  839. DueTime = CurrentTime + Period;
  840. }
  841. AbsoluteData->DueTime = DueTime;
  842. Timer->FunctionTable.Arm(Context, TimerModeAbsolute, DueTime);
  843. }
  844. }
  845. return;
  846. }
  847. ULONGLONG
  848. HlpTimerExtendedQuery (
  849. PHARDWARE_TIMER Timer
  850. )
  851. /*++
  852. Routine Description:
  853. This routine returns a 64-bit monotonically non-decreasing value based on
  854. the given timer. For this routine to ensure the non-decreasing part, this
  855. routine must be called at more than twice the rollover rate. The inner
  856. workings of this routine rely on observing the top bit of the hardware
  857. timer each time it changes.
  858. Arguments:
  859. Timer - Supplies the timer to query.
  860. Return Value:
  861. Returns the timers count, with software rollovers extended out to 64-bits
  862. if needed.
  863. --*/
  864. {
  865. ULONGLONG Count1;
  866. ULONGLONG Count2;
  867. volatile ULONGLONG *CurrentCountPointer;
  868. ULONGLONG HardwareMask;
  869. ULONGLONG HardwareValue;
  870. ULONGLONG MostSignificantHardwareBit;
  871. ULONGLONG NewCount;
  872. PTIMER_READ_COUNTER ReadCounter;
  873. ULONGLONG SoftwareOffset1;
  874. ULONGLONG SoftwareOffset2;
  875. ReadCounter = Timer->FunctionTable.ReadCounter;
  876. ASSERT(ReadCounter != NULL);
  877. if (Timer->CurrentCounts == NULL) {
  878. CurrentCountPointer = &(Timer->CurrentCount);
  879. } else {
  880. CurrentCountPointer =
  881. &(Timer->CurrentCounts[KeGetCurrentProcessorNumber()]);
  882. }
  883. //
  884. // Get a consistent read between the hardware counter and current count
  885. // with respect to the software offset. The current count needs to be read
  886. // twice to avoid a torn read that could result from a race with the
  887. // extended read's atomic update from either another core or an interrupt
  888. // arriving on top of this loop.
  889. //
  890. do {
  891. READ_INT64_SYNC(&(Timer->SoftwareOffset), &SoftwareOffset1);
  892. Count1 = *CurrentCountPointer;
  893. HardwareValue = ReadCounter(Timer->PrivateContext);
  894. READ_INT64_SYNC(&(Timer->SoftwareOffset), &SoftwareOffset2);
  895. Count2 = *CurrentCountPointer;
  896. } while ((SoftwareOffset1 != SoftwareOffset2) || (Count1 != Count2));
  897. //
  898. // For 64-bit timers, just return the raw timer, no software rollover
  899. // accounting is needed.
  900. //
  901. if (Timer->CounterBitWidth >= 64) {
  902. return HardwareValue + SoftwareOffset1;
  903. }
  904. MostSignificantHardwareBit = 1ULL << (Timer->CounterBitWidth - 1);
  905. HardwareMask = (1ULL << Timer->CounterBitWidth) - 1;
  906. //
  907. // The new count is the old count, but with the hardware timer replacing
  908. // the lower bits.
  909. //
  910. NewCount = (Count1 & ~HardwareMask) | HardwareValue;
  911. //
  912. // If the most significant bit has flipped, the new count will need to
  913. // be written back into the global.
  914. //
  915. if (((NewCount ^ Count1) & MostSignificantHardwareBit) != 0) {
  916. //
  917. // Add a rollover if the transition was from a 1 to a 0.
  918. //
  919. if ((NewCount & MostSignificantHardwareBit) == 0) {
  920. NewCount += HardwareMask + 1;
  921. }
  922. //
  923. // Compare exchange the new count with the global. If the compare
  924. // exchange was won, then the value is nicely updated. If the compare
  925. // exchange was lost, then someone else must have done the update, and
  926. // no further action is needed (as both parties will have added the
  927. // rollover independently if necessary).
  928. //
  929. RtlAtomicCompareExchange64(CurrentCountPointer, NewCount, Count1);
  930. }
  931. return NewCount + SoftwareOffset1;
  932. }
  933. ULONGLONG
  934. HlpTimerTimeToTicks (
  935. PHARDWARE_TIMER Timer,
  936. ULONGLONG TimeIn100ns
  937. )
  938. /*++
  939. Routine Description:
  940. This routine returns the tick count that best approximates the desired
  941. time interval on the given timer.
  942. Arguments:
  943. Timer - Supplies a pointer to the timer on which this interval will be
  944. run.
  945. TimeIn100ns - Supplies the desired interval to fire in, with units of
  946. 100 nanoseconds (10^-7 seconds).
  947. Return Value:
  948. Returns the tick count that most closely approximates the requested tick
  949. count.
  950. 0 on failure.
  951. --*/
  952. {
  953. ULONGLONG HalfRolloverTicks;
  954. ULONGLONG MaxTimerValue;
  955. ULONGLONG TickCount;
  956. //
  957. // The tick count is the frequency (ticks / s) * Time (hns) /
  958. // 10^7 (s / hns). All units cancel but ticks.
  959. //
  960. TickCount = Timer->CounterFrequency * TimeIn100ns / 10000000ULL;
  961. if (TickCount == 0) {
  962. TickCount = 1;
  963. }
  964. //
  965. // If the requested tick count is more than the timer can handle, return
  966. // the maximum value the timer can handle.
  967. //
  968. if (Timer->CounterBitWidth < 64) {
  969. MaxTimerValue = (1ULL << Timer->CounterBitWidth) - 1;
  970. if (TickCount > MaxTimerValue) {
  971. TickCount = MaxTimerValue;
  972. }
  973. }
  974. //
  975. // If this is a non-periodic absolute timer, then the tick count needs to
  976. // be truncated to half the rollover rate. Otherwise it is difficult for
  977. // the timer to detect if an absolute time is shortly in the past or
  978. // far in the future.
  979. //
  980. if (((Timer->Features & TIMER_FEATURE_ABSOLUTE) != 0) &&
  981. ((Timer->Features & TIMER_FEATURE_PERIODIC) == 0)) {
  982. HalfRolloverTicks = 1ULL << (Timer->CounterBitWidth - 1);
  983. if (TickCount > HalfRolloverTicks) {
  984. TickCount = HalfRolloverTicks;
  985. }
  986. }
  987. return TickCount;
  988. }
  989. //
  990. // --------------------------------------------------------- Internal Functions
  991. //
  992. KSTATUS
  993. HlpTimerInitialize (
  994. PHARDWARE_TIMER Timer
  995. )
  996. /*++
  997. Routine Description:
  998. This routine initializes or reinitializes a hardware timer.
  999. Arguments:
  1000. Timer - Supplies a pointer to the timer to initialize or
  1001. reinitialize.
  1002. Return Value:
  1003. Status code.
  1004. --*/
  1005. {
  1006. PTIMER_INITIALIZE Initialize;
  1007. KSTATUS Status;
  1008. //
  1009. // Reinitialize the timer.
  1010. //
  1011. Initialize = Timer->FunctionTable.Initialize;
  1012. Status = Initialize(Timer->PrivateContext);
  1013. if (!KSUCCESS(Status)) {
  1014. goto TimerInitializeEnd;
  1015. }
  1016. TimerInitializeEnd:
  1017. if (KSUCCESS(Status)) {
  1018. Timer->Flags &= ~TIMER_FLAG_FAILED;
  1019. Timer->Flags |= TIMER_FLAG_INITIALIZED;
  1020. } else {
  1021. Timer->Flags &= ~TIMER_FLAG_INITIALIZED;
  1022. Timer->Flags |= TIMER_FLAG_FAILED;
  1023. }
  1024. return Status;
  1025. }
  1026. KSTATUS
  1027. HlpTimerMeasureUnknownFrequencies (
  1028. VOID
  1029. )
  1030. /*++
  1031. Routine Description:
  1032. This routine measures the timers whose frequencies are not currently known.
  1033. Arguments:
  1034. None.
  1035. Return Value:
  1036. Status code.
  1037. --*/
  1038. {
  1039. PLIST_ENTRY CurrentEntry;
  1040. PULONGLONG EndTimes;
  1041. PHARDWARE_TIMER MeasuringTimer;
  1042. PULONGLONG StartTimes;
  1043. KSTATUS Status;
  1044. PHARDWARE_TIMER Timer;
  1045. ULONG TimerCount;
  1046. ULONG TimerIndex;
  1047. StartTimes = NULL;
  1048. //
  1049. // Find and initialize the timer that should be used to measure all other
  1050. // timers.
  1051. //
  1052. while (TRUE) {
  1053. MeasuringTimer = HlpTimerFindIdealMeasuringSource();
  1054. if (MeasuringTimer == NULL) {
  1055. Status = STATUS_NO_ELIGIBLE_DEVICES;
  1056. goto TimerMeasureUnknownFrequenciesEnd;
  1057. }
  1058. Status = HlpTimerInitialize(MeasuringTimer);
  1059. if (!KSUCCESS(Status)) {
  1060. continue;
  1061. }
  1062. break;
  1063. }
  1064. //
  1065. // Scan through all timers, and initialize the ones that need to be fired up
  1066. // to be measured.
  1067. //
  1068. TimerCount = 0;
  1069. CurrentEntry = HlTimers.Next;
  1070. while (CurrentEntry != &HlTimers) {
  1071. Timer = LIST_VALUE(CurrentEntry, HARDWARE_TIMER, ListEntry);
  1072. CurrentEntry = CurrentEntry->Next;
  1073. if (Timer->CounterFrequency == 0) {
  1074. Status = HlpTimerInitialize(Timer);
  1075. if (KSUCCESS(Status)) {
  1076. TimerCount += 1;
  1077. }
  1078. }
  1079. }
  1080. //
  1081. // If there's nothing to measure, don't even worry about it.
  1082. //
  1083. if (TimerCount == 0) {
  1084. Status = STATUS_SUCCESS;
  1085. goto TimerMeasureUnknownFrequenciesEnd;
  1086. }
  1087. //
  1088. // Allocate space to store the start and end times of all the timers.
  1089. //
  1090. StartTimes = MmAllocateNonPagedPool(TimerCount * sizeof(ULONGLONG) * 2,
  1091. HL_POOL_TAG);
  1092. if (StartTimes == NULL) {
  1093. Status = STATUS_INSUFFICIENT_RESOURCES;
  1094. goto TimerMeasureUnknownFrequenciesEnd;
  1095. }
  1096. RtlZeroMemory(StartTimes, TimerCount * sizeof(ULONGLONG) * 2);
  1097. EndTimes = StartTimes + TimerCount;
  1098. //
  1099. // Perform a "warm-up" read of all timers. This read clears the pipes,
  1100. // warming up caches and flushing out any hardware quirks associated with
  1101. // the "first" read.
  1102. //
  1103. TimerIndex = 0;
  1104. CurrentEntry = HlTimers.Next;
  1105. while (CurrentEntry != &HlTimers) {
  1106. Timer = LIST_VALUE(CurrentEntry, HARDWARE_TIMER, ListEntry);
  1107. CurrentEntry = CurrentEntry->Next;
  1108. if (((Timer->Flags & TIMER_FLAG_INITIALIZED) != 0) &&
  1109. (Timer->CounterFrequency == 0)) {
  1110. StartTimes[TimerIndex] = HlpTimerExtendedQuery(Timer);
  1111. TimerIndex += 1;
  1112. }
  1113. }
  1114. //
  1115. // Do a warm-up read of the measuring source and serializing instruction
  1116. // as well.
  1117. //
  1118. HlpTimerExtendedQuery(MeasuringTimer);
  1119. ArSerializeExecution();
  1120. //
  1121. // Mark the beginning time for each timer.
  1122. //
  1123. TimerIndex = 0;
  1124. CurrentEntry = HlTimers.Next;
  1125. while (CurrentEntry != &HlTimers) {
  1126. Timer = LIST_VALUE(CurrentEntry, HARDWARE_TIMER, ListEntry);
  1127. CurrentEntry = CurrentEntry->Next;
  1128. if (((Timer->Flags & TIMER_FLAG_INITIALIZED) != 0) &&
  1129. (Timer->CounterFrequency == 0)) {
  1130. StartTimes[TimerIndex] = HlpTimerExtendedQuery(Timer);
  1131. TimerIndex += 1;
  1132. }
  1133. }
  1134. //
  1135. // Serialize to ensure that all reads have actually occurred.
  1136. //
  1137. ArSerializeExecution();
  1138. //
  1139. // Stall for a quarter of a second against the reference timer.
  1140. //
  1141. HlpTimerBusyStall(MeasuringTimer, REFERENCE_STALL_DURATION);
  1142. //
  1143. // Serialize again to ensure the stall completed.
  1144. //
  1145. ArSerializeExecution();
  1146. //
  1147. // Take the end marking reads.
  1148. //
  1149. TimerIndex = 0;
  1150. CurrentEntry = HlTimers.Next;
  1151. while (CurrentEntry != &HlTimers) {
  1152. Timer = LIST_VALUE(CurrentEntry, HARDWARE_TIMER, ListEntry);
  1153. CurrentEntry = CurrentEntry->Next;
  1154. if (((Timer->Flags & TIMER_FLAG_INITIALIZED) != 0) &&
  1155. (Timer->CounterFrequency == 0)) {
  1156. EndTimes[TimerIndex] = HlpTimerExtendedQuery(Timer);
  1157. TimerIndex += 1;
  1158. }
  1159. }
  1160. //
  1161. // Whew, the time sensitive part is over. Now calculate the frequencies of
  1162. // all these bad boys.
  1163. //
  1164. TimerIndex = 0;
  1165. CurrentEntry = HlTimers.Next;
  1166. while (CurrentEntry != &HlTimers) {
  1167. Timer = LIST_VALUE(CurrentEntry, HARDWARE_TIMER, ListEntry);
  1168. CurrentEntry = CurrentEntry->Next;
  1169. if (((Timer->Flags & TIMER_FLAG_INITIALIZED) != 0) &&
  1170. (Timer->CounterFrequency == 0)) {
  1171. //
  1172. // Frequency is ticks per second. So take the number of ticks and
  1173. // divide by the number of seconds.
  1174. //
  1175. Timer->CounterFrequency =
  1176. (EndTimes[TimerIndex] - StartTimes[TimerIndex]) *
  1177. (1000000 / REFERENCE_STALL_DURATION);
  1178. if (Timer->CounterFrequency == 0) {
  1179. Timer->Flags |= TIMER_FLAG_FAILED | TIMER_FLAG_NOT_TICKING;
  1180. }
  1181. TimerIndex += 1;
  1182. }
  1183. }
  1184. Status = STATUS_SUCCESS;
  1185. TimerMeasureUnknownFrequenciesEnd:
  1186. if (StartTimes != NULL) {
  1187. MmFreeNonPagedPool(StartTimes);
  1188. }
  1189. return Status;
  1190. }
  1191. PHARDWARE_TIMER
  1192. HlpTimerFindIdealMeasuringSource (
  1193. VOID
  1194. )
  1195. /*++
  1196. Routine Description:
  1197. This routine attempts to find a timer suitable for measuring all other
  1198. timers.
  1199. Arguments:
  1200. None.
  1201. Return Value:
  1202. Returns a pointer to the timer on success.
  1203. NULL if no suitable timers could be found.
  1204. --*/
  1205. {
  1206. PHARDWARE_TIMER BestTimer;
  1207. PLIST_ENTRY CurrentEntry;
  1208. PHARDWARE_TIMER Timer;
  1209. BestTimer = NULL;
  1210. CurrentEntry = HlTimers.Next;
  1211. while (CurrentEntry != &HlTimers) {
  1212. Timer = LIST_VALUE(CurrentEntry, HARDWARE_TIMER, ListEntry);
  1213. CurrentEntry = CurrentEntry->Next;
  1214. //
  1215. // Look for a readable timer with the fastest frequency.
  1216. //
  1217. if ((Timer->Features & TIMER_FEATURE_READABLE) == 0) {
  1218. continue;
  1219. }
  1220. if (Timer->CounterFrequency == 0) {
  1221. continue;
  1222. }
  1223. if ((Timer->Flags & TIMER_FLAG_FAILED) != 0) {
  1224. continue;
  1225. }
  1226. if ((BestTimer == NULL) ||
  1227. (Timer->CounterFrequency > BestTimer->CounterFrequency)) {
  1228. BestTimer = Timer;
  1229. }
  1230. }
  1231. return BestTimer;
  1232. }
  1233. PHARDWARE_TIMER
  1234. HlpTimerFindIdealClockSource (
  1235. VOID
  1236. )
  1237. /*++
  1238. Routine Description:
  1239. This routine attempts to find a timer suitable for running the periodic
  1240. system clock interrupt.
  1241. Arguments:
  1242. None.
  1243. Return Value:
  1244. Returns a pointer to the timer on success.
  1245. NULL if no suitable timers could be found.
  1246. --*/
  1247. {
  1248. ULONG RequiredFeatures;
  1249. PHARDWARE_TIMER Timer;
  1250. RequiredFeatures = TIMER_FEATURE_PERIODIC | TIMER_FEATURE_PER_PROCESSOR;
  1251. Timer = HlpTimerFind(RequiredFeatures, 0, 0);
  1252. if (Timer != NULL) {
  1253. return Timer;
  1254. }
  1255. RequiredFeatures = TIMER_FEATURE_ABSOLUTE | TIMER_FEATURE_PER_PROCESSOR;
  1256. Timer = HlpTimerFind(RequiredFeatures, 0, 0);
  1257. if (Timer != NULL) {
  1258. return Timer;
  1259. }
  1260. Timer = HlpTimerFind(TIMER_FEATURE_PERIODIC, 0, 0);
  1261. if (Timer != NULL) {
  1262. return Timer;
  1263. }
  1264. return Timer;
  1265. }
  1266. PHARDWARE_TIMER
  1267. HlpTimerFindIdealProfilerSource (
  1268. VOID
  1269. )
  1270. /*++
  1271. Routine Description:
  1272. This routine attempts to find a timer suitable for running the periodic
  1273. system profiler.
  1274. Arguments:
  1275. None.
  1276. Return Value:
  1277. Returns a pointer to the timer on success.
  1278. NULL if no suitable timers could be found.
  1279. --*/
  1280. {
  1281. ULONG RequiredNonFeatures;
  1282. PHARDWARE_TIMER Timer;
  1283. //
  1284. // Attempt to find a periodic non-variable timer. It should not be
  1285. // per-processor.
  1286. //
  1287. RequiredNonFeatures = TIMER_FEATURE_PER_PROCESSOR | TIMER_FEATURE_VARIANT;
  1288. Timer = HlpTimerFind(TIMER_FEATURE_PERIODIC, RequiredNonFeatures, 0);
  1289. return Timer;
  1290. }
  1291. PHARDWARE_TIMER
  1292. HlpTimerFindIdealTimeCounter (
  1293. VOID
  1294. )
  1295. /*++
  1296. Routine Description:
  1297. This routine attempts to find a timer suitable for running the system's
  1298. concept of time.
  1299. Arguments:
  1300. None.
  1301. Return Value:
  1302. Returns a pointer to the timer on success.
  1303. NULL if no suitable timers could be found.
  1304. --*/
  1305. {
  1306. ULONG Options;
  1307. ULONG RequiredFeatures;
  1308. PHARDWARE_TIMER Timer;
  1309. //
  1310. // Attempt to find a per-processor timer for fastest access.
  1311. //
  1312. Options = FIND_TIMER_OPTION_INCLUDE_USED_FOR_INTERRUPT_ABSOLUTE;
  1313. RequiredFeatures = TIMER_FEATURE_PER_PROCESSOR | TIMER_FEATURE_READABLE;
  1314. Timer = HlpTimerFind(RequiredFeatures, TIMER_FEATURE_VARIANT, Options);
  1315. if (Timer != NULL) {
  1316. return Timer;
  1317. }
  1318. //
  1319. // Attempt to find any readable timer.
  1320. //
  1321. RequiredFeatures = TIMER_FEATURE_READABLE;
  1322. Timer = HlpTimerFind(RequiredFeatures, TIMER_FEATURE_VARIANT, Options);
  1323. if (Timer != NULL) {
  1324. return Timer;
  1325. }
  1326. return Timer;
  1327. }
  1328. PHARDWARE_TIMER
  1329. HlpTimerFindIdealProcessorCounter (
  1330. VOID
  1331. )
  1332. /*++
  1333. Routine Description:
  1334. This routine attempts to find a timer suitable for running the system's
  1335. concept of processor time, which may not line up well to wall clock time.
  1336. Performance is key here, as this counter is queried frequently by the
  1337. scheduler.
  1338. Arguments:
  1339. None.
  1340. Return Value:
  1341. Returns a pointer to the timer on success.
  1342. NULL if no suitable timers could be found.
  1343. --*/
  1344. {
  1345. ULONG Options;
  1346. PHARDWARE_TIMER Timer;
  1347. //
  1348. // Attempt to find the processor counter.
  1349. //
  1350. Options = FIND_TIMER_OPTION_INCLUDE_USED_FOR_COUNTER |
  1351. FIND_TIMER_OPTION_INCLUDE_USED_FOR_INTERRUPT_ABSOLUTE;
  1352. Timer = HlpTimerFind(TIMER_FEATURE_PROCESSOR_COUNTER, 0, Options);
  1353. if (Timer != NULL) {
  1354. return Timer;
  1355. }
  1356. //
  1357. // If for some reason there is no processor cycle counter, use the
  1358. // time counter.
  1359. //
  1360. return HlTimeCounter;
  1361. }
  1362. PHARDWARE_TIMER
  1363. HlpTimerFind (
  1364. ULONG RequiredFeatures,
  1365. ULONG RequiredNonFeatures,
  1366. ULONG FindOptions
  1367. )
  1368. /*++
  1369. Routine Description:
  1370. This routine attempts to find a timer matching the given characteristics.
  1371. Arguments:
  1372. RequiredFeatures - Supplies a bitfield of the features that the hardware
  1373. timer must implement.
  1374. RequiredNonFeatures - Supplies a bitfield of the features that the hardware
  1375. timer must NOT have implemented.
  1376. FindOptions - Supplies a bitfield of options governing additional parameters
  1377. of the search. See FIND_TIMER_OPTION_* definitions.
  1378. Return Value:
  1379. Returns a pointer to a timer matching the given criteria on success.
  1380. NULL if no timer matching the requested criteria could be found.
  1381. --*/
  1382. {
  1383. PLIST_ENTRY CurrentEntry;
  1384. PHARDWARE_TIMER Timer;
  1385. BOOL TimerFound;
  1386. Timer = NULL;
  1387. TimerFound = FALSE;
  1388. CurrentEntry = HlTimers.Next;
  1389. while (CurrentEntry != &HlTimers) {
  1390. Timer = LIST_VALUE(CurrentEntry, HARDWARE_TIMER, ListEntry);
  1391. CurrentEntry = CurrentEntry->Next;
  1392. //
  1393. // Skip this timer if it does not have the required features set.
  1394. //
  1395. if ((Timer->Features & RequiredFeatures) != RequiredFeatures) {
  1396. continue;
  1397. }
  1398. //
  1399. // Skip this timer if it has any of the non-features set.
  1400. //
  1401. if ((Timer->Features & RequiredNonFeatures) != 0) {
  1402. continue;
  1403. }
  1404. //
  1405. // Unless the include used option is set, skip this timer if it's
  1406. // already marked as in use.
  1407. //
  1408. if (((Timer->Flags & TIMER_FLAG_IN_USE_FOR_INTERRUPT) != 0) &&
  1409. ((FindOptions &
  1410. FIND_TIMER_OPTION_INCLUDE_USED_FOR_INTERRUPT_ANY) == 0)) {
  1411. if ((FindOptions &
  1412. FIND_TIMER_OPTION_INCLUDE_USED_FOR_INTERRUPT_ABSOLUTE) == 0) {
  1413. continue;
  1414. }
  1415. if ((Timer->Features & TIMER_FEATURE_ABSOLUTE) == 0) {
  1416. continue;
  1417. }
  1418. }
  1419. if ((FindOptions & FIND_TIMER_OPTION_INCLUDE_USED_FOR_COUNTER) == 0) {
  1420. if ((Timer->Flags & TIMER_FLAG_IN_USE_FOR_COUNTER) != 0) {
  1421. continue;
  1422. }
  1423. }
  1424. //
  1425. // Skip this timer if it has failed initialization.
  1426. //
  1427. if ((Timer->Flags & TIMER_FLAG_FAILED) != 0) {
  1428. continue;
  1429. }
  1430. //
  1431. // The timer doesn't not match all the required criteria... so return
  1432. // it.
  1433. //
  1434. TimerFound = TRUE;
  1435. break;
  1436. }
  1437. if (TimerFound != FALSE) {
  1438. return Timer;
  1439. }
  1440. return NULL;
  1441. }
  1442. VOID
  1443. HlpTimerBusyStall (
  1444. PHARDWARE_TIMER Timer,
  1445. ULONG Microseconds
  1446. )
  1447. /*++
  1448. Routine Description:
  1449. This routine executes for at least the given number of microseconds by
  1450. continually reading the given timer until the specified duration has passed
  1451. (as measured by that timer).
  1452. Arguments:
  1453. Timer - Supplies the timer to use as the reference for stalling.
  1454. Microseconds - Supplies the number of microseconds to stall for.
  1455. Return Value:
  1456. None.
  1457. --*/
  1458. {
  1459. ULONGLONG EndCount;
  1460. ULONG TickCount;
  1461. TickCount = (ULONGLONG)Microseconds * Timer->CounterFrequency / 1000000ULL;
  1462. //
  1463. // The end count is a read of the timer plus the number of ticks to stall
  1464. // for.
  1465. //
  1466. EndCount = HlpTimerExtendedQuery(Timer) + TickCount;
  1467. //
  1468. // Loop until the timer's count exceeds the end time.
  1469. //
  1470. while (HlpTimerExtendedQuery(Timer) < EndCount) {
  1471. ArProcessorYield();
  1472. }
  1473. return;
  1474. }
  1475. KSTATUS
  1476. HlpTimerAssignRoles (
  1477. VOID
  1478. )
  1479. /*++
  1480. Routine Description:
  1481. This routine surveys the timers registered across the system and assigns
  1482. them to the various required system services.
  1483. Arguments:
  1484. None.
  1485. Return Value:
  1486. Status code.
  1487. --*/
  1488. {
  1489. KSTATUS Status;
  1490. PHARDWARE_TIMER Timer;
  1491. //
  1492. // Assign the clock role.
  1493. //
  1494. while (TRUE) {
  1495. Timer = HlpTimerFindIdealClockSource();
  1496. if (Timer == NULL) {
  1497. Status = STATUS_NO_ELIGIBLE_DEVICES;
  1498. goto TimerAssignRolesEnd;
  1499. }
  1500. Status = HlpTimerInitialize(Timer);
  1501. if (KSUCCESS(Status)) {
  1502. HlClockTimer = Timer;
  1503. Timer->Flags |= TIMER_FLAG_IN_USE_FOR_INTERRUPT;
  1504. break;
  1505. }
  1506. }
  1507. //
  1508. // Assign the time counter role.
  1509. //
  1510. while (TRUE) {
  1511. Timer = HlpTimerFindIdealTimeCounter();
  1512. if (Timer == NULL) {
  1513. Status = STATUS_NO_ELIGIBLE_DEVICES;
  1514. goto TimerAssignRolesEnd;
  1515. }
  1516. Status = HlpTimerInitialize(Timer);
  1517. if (KSUCCESS(Status)) {
  1518. HlTimeCounter = Timer;
  1519. Timer->Flags |= TIMER_FLAG_IN_USE_FOR_COUNTER;
  1520. break;
  1521. }
  1522. }
  1523. //
  1524. // Assign the processor counter role.
  1525. //
  1526. while (TRUE) {
  1527. Timer = HlpTimerFindIdealProcessorCounter();
  1528. if (Timer == NULL) {
  1529. Status = STATUS_NO_ELIGIBLE_DEVICES;
  1530. goto TimerAssignRolesEnd;
  1531. }
  1532. if ((Timer->Flags & TIMER_FLAG_INITIALIZED) == 0) {
  1533. Status = HlpTimerInitialize(Timer);
  1534. } else {
  1535. Status = STATUS_SUCCESS;
  1536. }
  1537. if (KSUCCESS(Status)) {
  1538. HlProcessorCounter = Timer;
  1539. Timer->Flags |= TIMER_FLAG_IN_USE_FOR_COUNTER;
  1540. break;
  1541. }
  1542. }
  1543. //
  1544. // Assign the profiler role. If there are no available timers, still
  1545. // succeeded. The system just will not be able to be profiled.
  1546. //
  1547. while (TRUE) {
  1548. Timer = HlpTimerFindIdealProfilerSource();
  1549. if (Timer == NULL) {
  1550. ASSERT(HlProfilerTimer == NULL);
  1551. Status = STATUS_SUCCESS;
  1552. goto TimerAssignRolesEnd;
  1553. }
  1554. Status = HlpTimerInitialize(Timer);
  1555. if (KSUCCESS(Status)) {
  1556. HlProfilerTimer = Timer;
  1557. Timer->Flags |= TIMER_FLAG_IN_USE_FOR_INTERRUPT;
  1558. break;
  1559. }
  1560. }
  1561. Status = STATUS_SUCCESS;
  1562. TimerAssignRolesEnd:
  1563. return Status;
  1564. }
  1565. VOID
  1566. HlpTimerResetCounterOffset (
  1567. PHARDWARE_TIMER Timer,
  1568. ULONGLONG NewValue
  1569. )
  1570. /*++
  1571. Routine Description:
  1572. This routine resets the software offset of the given timer to make it
  1573. appear as if the counter is starting from the given value.
  1574. Arguments:
  1575. Timer - Supplies a pointer to the timer to reset.
  1576. NewValue - Supplies a pointer to the new value to make extended reads
  1577. return.
  1578. Return Value:
  1579. None.
  1580. --*/
  1581. {
  1582. ULONGLONG Counter;
  1583. ULONGLONG NewOffset;
  1584. ASSERT((Timer->Features & TIMER_FEATURE_READABLE) != 0);
  1585. Counter = Timer->FunctionTable.ReadCounter(Timer->PrivateContext);
  1586. //
  1587. // Extended reads are Counter + Offset = Value. Flip the equation around and
  1588. // it becomes Offset = Value - Counter.
  1589. //
  1590. NewOffset = NewValue - Counter;
  1591. WRITE_INT64_SYNC(&(Timer->SoftwareOffset), NewOffset);
  1592. return;
  1593. }
  1594. KSTATUS
  1595. HlpTimerCreateSoftUpdateTimer (
  1596. PHARDWARE_TIMER Timer
  1597. )
  1598. /*++
  1599. Routine Description:
  1600. This routine creates a software timer that fires a little more frequently
  1601. than half the timer rollover rate. This is used to ensure that each
  1602. significant bit flip of the timer is observed. If the timer's counter is
  1603. 64-bits in length, then no timer is created.
  1604. Arguments:
  1605. Timer - Supplies a pointer to the timer to create the software timer for.
  1606. Return Value:
  1607. Status code.
  1608. --*/
  1609. {
  1610. ULONGLONG HalfRolloverSeconds;
  1611. ULONGLONG Microseconds;
  1612. PKTIMER SoftTimer;
  1613. KSTATUS Status;
  1614. ULONG Ticks;
  1615. //
  1616. // Do nothing if the timer is 64-bits (and so there's no rollover to keep
  1617. // track of).
  1618. //
  1619. if (Timer->CounterBitWidth == 64) {
  1620. return STATUS_SUCCESS;
  1621. }
  1622. //
  1623. // Compute the half rollover rate in seconds. If it's huge, then also don't
  1624. // bother with a software timer.
  1625. //
  1626. Ticks = 1ULL << (Timer->CounterBitWidth - 1);
  1627. HalfRolloverSeconds = Ticks / Timer->CounterFrequency;
  1628. if (HalfRolloverSeconds > (SECONDS_PER_DAY * 90)) {
  1629. return STATUS_SUCCESS;
  1630. }
  1631. //
  1632. // Figure out the microseconds per half-rollover, and then take about 80
  1633. // percent of that for safety.
  1634. //
  1635. Microseconds = (Ticks * MICROSECONDS_PER_SECOND) / Timer->CounterFrequency;
  1636. Microseconds = (Microseconds * 820) / 1024;
  1637. //
  1638. // Create the timer, which itself is leaked. If this function is needed by
  1639. // timers other than the time counter, then 1) the timer should be saved
  1640. // in the hardware timer structure so that it can be shut off if the timer
  1641. // is no longer used, and 2) the timer should fire a DPC that actually
  1642. // queries the counter (rather than assuming the clock interrupt will do it,
  1643. // which is true only for the time counter).
  1644. //
  1645. ASSERT(Timer == HlTimeCounter);
  1646. SoftTimer = KeCreateTimer(HL_POOL_TAG);
  1647. if (SoftTimer == NULL) {
  1648. return STATUS_INSUFFICIENT_RESOURCES;
  1649. }
  1650. //
  1651. // Now convert those microseconds to time counter ticks and queue the timer.
  1652. //
  1653. Ticks = KeConvertMicrosecondsToTimeTicks(Microseconds);
  1654. Status = KeQueueTimer(SoftTimer, TimerQueueSoftWake, 0, Ticks, 0, NULL);
  1655. return Status;
  1656. }