Windows NT 4.0 source code leak
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.

471 lines
13 KiB

4 years ago
  1. // "@(#) NEC r98clock.s 1.10 95/02/20 17:04:37"
  2. // TITLE("Interval and Profile Clock Interrupts")
  3. //++
  4. //
  5. // Copyright (c) 1991-1994 Microsoft Corporation
  6. //
  7. // Module Name:
  8. //
  9. // r98clock.s
  10. //
  11. // Abstract:
  12. //
  13. // This module implements the code necessary to field and process the
  14. // interval and profile clock interrupts on a MIPS R4000 system.
  15. //
  16. //--
  17. //
  18. // Original source: Build Number 1.612
  19. //
  20. // Modify for R98(MIPS/R4400)
  21. //
  22. //***********************************************************************
  23. //
  24. // M001 94.03/16-5/31 T.Samezima
  25. //
  26. // change header file from duo to r98
  27. // change value of use to update of parformance counter
  28. // initial value of count register
  29. //
  30. // del clear interrupt
  31. //
  32. //***********************************************************************
  33. //
  34. // S002 94.6/13 T.Samezima
  35. //
  36. // Del Compile err
  37. //
  38. //
  39. //***********************************************************************
  40. //
  41. // S003 94.7/19 T.Samezima
  42. //
  43. // Chg Function interface change
  44. //
  45. //***********************************************************************
  46. //
  47. // S004 94.7/19 T.Samezima
  48. //
  49. // Bug PMC register address is not change of KSEG1_BASE
  50. //
  51. //***********************************************************************
  52. //
  53. // S005 94.10/12 T.Samezima
  54. //
  55. // Fix Version Up at build807
  56. //
  57. // S006 '94.10/14 T.Samezima
  58. // Chg Logic of set interval count
  59. //
  60. // S007 '94.01/11 T.Samezima
  61. // Del delete 'if NT_UP'.
  62. //
  63. // S008 '94.01/16 T.Samezima
  64. // Add Check ECC 1bit err flag and enable ECC 1bit err.
  65. //
  66. //
  67. #include "halmips.h"
  68. // Start M001
  69. #if defined(_R98_)
  70. #include "r98def.h"
  71. // #include "r98reg.h" // S002
  72. #else // if defined(_R98_)
  73. #if defined(_DUO_)
  74. #include "duodef.h"
  75. #endif
  76. #if defined(_JAZZ_)
  77. #include "jazzdef.h"
  78. #endif
  79. #endif // #if !defined(_R98_)
  80. // End M001
  81. #define ECC_ERROR_COUNT_LIMIT 1 // S008
  82. SBTTL("System Clock Interrupt - Processor 0")
  83. //++
  84. //
  85. // Routine Description:
  86. //
  87. // This routine is entered as the result of an interrupt generated by
  88. // the interval timer. Its function is to acknowledge the interrupt and
  89. // transfer control to the standard system routine to update the system
  90. // time and the execution time of the current thread and process.
  91. //
  92. // Arguments:
  93. //
  94. // a0 - Supplies a pointer to a trap frame. // S003
  95. //
  96. // Return Value:
  97. //
  98. // None.
  99. //
  100. //--
  101. .struct 0
  102. CiArgs: .space 4 * 4 // saved arguments
  103. .space 3 * 4 // fill
  104. CiRa: .space 4 // saved return address
  105. CiFrameLength: //
  106. NESTED_ENTRY(HalpClockInterrupt0, CiFrameLength, zero)
  107. subu sp,sp,CiFrameLength // allocate stack frame
  108. sw ra,CiRa(sp) // save return address
  109. PROLOGUE_END
  110. // Start M001
  111. #if !defined(_R98_)
  112. .set noreorder
  113. #if defined(_DUO_)
  114. lw t0,DMA_VIRTUAL_BASE + 0x58 // acknowledge timer interrupt
  115. #endif
  116. #if defined(_JAZZ_)
  117. lw t0,DMA_VIRTUAL_BASE + 0x230 // acknowledge timer interrupt
  118. #endif
  119. .set reorder
  120. #endif // #if !defined(_R98_)
  121. // End M001
  122. // S003
  123. // move a0,s8 // set address of trap frame
  124. lw a1,HalpCurrentTimeIncrement // set current time increment
  125. lw t0,__imp_KeUpdateSystemTime // update system time // S005
  126. jal t0 // // S005
  127. //
  128. // The following code is a work around for a bug in the Fusion machines
  129. // where the clock interrupt is not dismissed by reading the acknowledge
  130. // register.
  131. //
  132. // Start M001
  133. #if !defined(_R98_)
  134. #if defined(_JAZZ_)
  135. .set noreorder
  136. .set noat
  137. mfc0 t0,cause // read the cause register
  138. lw t1,HalpEisaControlBase // get EISA control base address
  139. sll t0,t0,31 - (CAUSE_INTPEND + CLOCK_LEVEL - 1) // isolate clock bit
  140. bgez t0,10f // if gez, no clock interrupt pending
  141. li t2,0x2 // get NMI port enable bit
  142. lb t3,0x70(t1) // save EISA NMI interrupt disable
  143. lb t4,0x461(t1) // save EISA extended NMI status
  144. sb zero,0x70(t1) // clear EISA NMI interrupt disable
  145. sb t2,0x461(t1) // set EISA NMI port enable
  146. sb zero,0x462(t1) // generate EISA NMI interrupt
  147. sb zero,0x461(t1) // clear EISA extended NMI status
  148. sb t2,0x461(t1) //
  149. lb zero,0x461(t1) // synchronize clear operatin
  150. sb t3,0x70(t1) // restore EISA NMI interupt disable
  151. sb t4,0x461(t1) // restore EISA exteneed NMI status
  152. lb zero,0x461(t1) // synchronize restore operation
  153. .set at
  154. .set reorder
  155. 10: //
  156. #endif
  157. #endif // #if !defined(_R98_)
  158. // End M001
  159. // S008 vvv
  160. //
  161. // Check ECC 1bit error flag.
  162. //
  163. lw t0,HalpECC1bitDisableTime // get value of disable time
  164. beq zero,t0,10f // if ne, check ecc 1bit
  165. lw t1,HalpCurrentTimeIncrement // get current time increment
  166. subu t0,t0,t1 // declement disable time
  167. sw t0,HalpECC1bitDisableTime //
  168. blez t0,5f // if lez, enable ecc 1bit
  169. beq zero,zero,10f // not lez,
  170. 5: sw zero,HalpECC1bitDisableTime // clear disable time
  171. li t0,ECC_ERROR_COUNT_LIMIT // set new flag
  172. sw t0,HalpECC1bitDisableFlag //
  173. la t1,KSEG1_BASE+SIC_PHYSICAL_BASE+SIC_DATA_OFFSET+SIC_SET0_OFFSET
  174. sw zero,0x0(t1) // enable ECC 1bit error
  175. lw t0,HalpECC1bitScfrBuffer // check connect to SIC1
  176. andi t0,SCFR_SIC_SET1_CONNECT //
  177. bne t0,zero,10f //
  178. la t1,KSEG1_BASE+SIC_PHYSICAL_BASE+SIC_DATA_OFFSET+SIC_SET1_OFFSET
  179. sw zero,0x0(t1) // enable ECC 1bit error
  180. // S008 ^^^
  181. //
  182. // At each clock interrupt the next time increment is moved to the current
  183. // time increment to "pipeline" the update of the current increment at the
  184. // correct time. If the next interval count is nonzero, then the new time
  185. // increment is moved to the next time increment and the next interval count
  186. // register is loaded with the specified interval count minus one (i.e., ms).
  187. //
  188. 10: lw t0,KdDebuggerEnabled // get address of debugger enable // S008
  189. lw t1,HalpNextIntervalCount // get next interval count
  190. lw t2,HalpNextTimeIncrement // get the next increment value
  191. lbu t0,0(t0) // get debugger enable flag
  192. lw t3,HalpNewTimeIncrement // get new new time increment value
  193. lw ra,CiRa(sp) // restore return address
  194. or t4,t1,t0 // set interval count or debugger?
  195. sw t2,HalpCurrentTimeIncrement // set current increment value
  196. bne zero,t4,20f // if ne, interval change or debugger
  197. addu sp,sp,CiFrameLength // deallocate stack frame
  198. j ra // return
  199. //
  200. // The interval count must be changed or the debugger is enabled.
  201. //
  202. 20: sw zero,HalpNextIntervalCount // clear next interval count
  203. beq zero,t1,30f // if eq, not interval count change
  204. subu t1,t1,1 // compute millisecond interval count
  205. // Start M001
  206. .set noreorder
  207. #if !defined(_R98_)
  208. #if defined(_DUO_)
  209. sw t1,DMA_VIRTUAL_BASE + 0x1a8 // set next interval count
  210. #endif
  211. #if defined(_JAZZ_)
  212. sw t1,DMA_VIRTUAL_BASE + 0x228 // set next interval count
  213. #endif
  214. # else // #if !defined(_R98_)
  215. sw t1,KSEG1_BASE+PMC_PHYSICAL_BASE1+PMC_LOCAL_OFFSET+0x40(zero) // S004
  216. #endif // #if !defined(_R98_)
  217. .set reorder
  218. // End M001
  219. sw t3,HalpNextTimeIncrement // set next time increment value
  220. 30: beq zero,t0,40f // if eq, debugger not enabled
  221. jal KdPollBreakIn // check if breakin is requested
  222. beq zero,v0,40f // if eq, no breakin requested
  223. li a0,DBG_STATUS_CONTROL_C // break in and send
  224. jal DbgBreakPointWithStatus // status to debugger
  225. 40: lw ra,CiRa(sp) // restore return address
  226. addu sp,sp,CiFrameLength // deallocate stack frame
  227. j ra // return
  228. .end HalpClockInterrupt0
  229. SBTTL("System Clock Interrupt - Processor N")
  230. //++
  231. //
  232. // Routine Description:
  233. //
  234. // This routine is entered as the result of an interrupt generated by
  235. // the interval timer. Its function is to acknowledge the interrupt
  236. // and transfer control to the standard system routine to update the
  237. // execution time of the current thread and process.
  238. //
  239. // Arguments:
  240. //
  241. // a0 - Supplies a pointer to a trap frame. // S003
  242. //
  243. // Return Value:
  244. //
  245. // None.
  246. //
  247. //--
  248. LEAF_ENTRY(HalpClockInterrupt1)
  249. #if !defined(_R98_)
  250. #if defined(_DUO_)
  251. lw t0,DMA_VIRTUAL_BASE + 0x58 // acknowledge timer interrupt
  252. move a0,s8 // set address of trap frame
  253. j KeUpdateRunTime // update system time
  254. #endif
  255. #else // #if !defined(_R98_)
  256. lw t1,KiPcr + PcPrcb(zero) // get current processor block address
  257. // S006 vvv
  258. la t2,HalpChangeIntervalFlg // get change flag of timer interval
  259. lbu t1,PbNumber(t1) // get processor number
  260. add t2,t1,t2 // check flag
  261. lb t1,0x0(t2) // get change flag of this CPU
  262. beq t1,zero,10f // if eq, no change timer interval
  263. sb zero,0x0(t2) // clear change flag of timer interval
  264. // S006 ^^^
  265. lw t1,HalpChangeIntervalCount // get next interval count
  266. sw t1,KSEG1_BASE+PMC_PHYSICAL_BASE1+PMC_LOCAL_OFFSET+0x40(zero) // S004
  267. // Start S003, S005
  268. //10: move a0,s8 // set address of trap frame
  269. 10: lw t1,__imp_KeUpdateRunTime // update system runtime
  270. j t1 //
  271. // End S003, S005
  272. #endif // #if !defined(_R98_)
  273. .end HalpClockInterrupt1
  274. SBTTL("Profile Clock Interrupt")
  275. //++
  276. //
  277. // Routine Description:
  278. //
  279. // This routine is entered as the result of an interrupt generated by the
  280. // profile clock. Its function is to acknowledge the profile interrupt,
  281. // compute the next compare value, update the performance counter, and
  282. // transfer control to the standard system routine to process any active
  283. // profiles.
  284. //
  285. // Arguments:
  286. //
  287. // a0 - Supplies a pointer to a trap frame. // S003
  288. //
  289. // Return Value:
  290. //
  291. // None.
  292. //
  293. //--
  294. LEAF_ENTRY(HalpProfileInterrupt)
  295. .set noreorder
  296. .set noat
  297. // Start M001
  298. mfc0 t0,count // get current count value
  299. addu t1,zero,3 // set initial count value
  300. mtc0 t1,count // set new count register value
  301. // End M001
  302. .set at
  303. .set reorder
  304. #if 0 // S007
  305. //#if defined(NT_UP)
  306. la t1,HalpPerformanceCounter // get performance counter address
  307. //#else
  308. #endif
  309. lw t1,KiPcr + PcPrcb(zero) // get current processor block address
  310. la t2,HalpPerformanceCounter // get performance counter address
  311. lbu t1,PbNumber(t1) // get processor number
  312. sll t1,t1,3 // compute address of performance count
  313. addu t1,t1,t2 //
  314. // #endif // S007
  315. lw t2,LiLowPart(t1) // get low part of performance count
  316. lw t3,LiHighPart(t1) // get high part of performance count
  317. addu t2,t2,t0 // update low part of performance count
  318. sw t2,LiLowPart(t1) // store low part of performance count
  319. sltu t4,t2,t0 // generate carry into high part
  320. addu t3,t3,t4 // update high part of performance count
  321. sw t3,LiHighPart(t1) // store high part of performance count
  322. // move a0,s8 // set address of trap frame // S003
  323. lw t4,__imp_KeProfileInterrupt // process profile interrupt // S005
  324. j t4 // // S005
  325. .end HalpProfileInterrupt
  326. SBTTL("Read Count Register")
  327. //++
  328. //
  329. // ULONG
  330. // HalpReadCountRegister (
  331. // VOID
  332. // );
  333. //
  334. // Routine Description:
  335. //
  336. // This routine reads the current value of the count register and
  337. // returns the value.
  338. //
  339. // Arguments:
  340. //
  341. // None.
  342. //
  343. // Return Value:
  344. //
  345. // Current value of the count register.
  346. //
  347. //--
  348. LEAF_ENTRY(HalpReadCountRegister)
  349. .set noreorder
  350. .set noat
  351. mfc0 v0,count // get count register value
  352. .set at
  353. .set reorder
  354. j ra // return
  355. .end HalpReadCountRegister
  356. SBTTL("Write Compare Register And Clear")
  357. //++
  358. //
  359. // ULONG
  360. // HalpWriteCompareRegisterAndClear (
  361. // IN ULONG Value
  362. // );
  363. //
  364. // Routine Description:
  365. //
  366. // This routine reads the current value of the count register, writes
  367. // the value of the compare register, clears the count register, and
  368. // returns the previous value of the count register.
  369. //
  370. // Arguments:
  371. //
  372. // Value - Supplies the value written to the compare register.
  373. //
  374. // Return Value:
  375. //
  376. // Previous value of the count register.
  377. //
  378. //--
  379. LEAF_ENTRY(HalpWriteCompareRegisterAndClear)
  380. .set noreorder
  381. .set noat
  382. mfc0 v0,count // get count register value
  383. mtc0 a0,compare // set compare register value
  384. li t0,7 // set lost cycle count
  385. mtc0 t0,count // set count register to zero
  386. .set at
  387. .set reorder
  388. j ra // return
  389. .end HalpWriteCompareRegisterAndClear