
ICNTR_supported	EQU	10h	; Pentium flag:	supporting cycle counter
	
ifndef SMP
	;; Define following if UP
	KI_STATE_IDLE	EQU	0
	KI_STATE_BUSY	EQU	8
	KI_STATE_INTR	EQU	16
endif


;;; Macro to turn on a hook for kernel idleness measurement
KITurnOn MACRO	hname,inst
	EXTRN	HookKI_&hname&_entry&inst&:NEAR
	;; 9C -- pushfd, FA -- cli
	mov	WORD PTR HookKI_&hname&_entry&inst&, 0FA9Ch
ENDM

;;; Macro to turn off a hook for kenel idleness measurement
KITurnOff MACRO hname,inst
	EXTRN   HookKI_&hname&_entry&inst&:NEAR
	EXTRN   HookKI_&hname&_exit&inst&:NEAR
	mov	eax, OFFSET FLAT:HookKI_&hname&_exit&inst&  ; hook exit addr
	sub	eax, OFFSET FLAT:HookKI_&hname&_entry&inst& ; subtract hook entry addr
	sub	eax, 2					    ; subtract next instr
	mov	ah, al
	mov	al, 0EBh				    ; jmp short intr
	mov	WORD PTR HookKI_&hname&_entry&inst&, ax
ENDM

;;; Macro to change code to use 8254 chip timer instead of
;;; Pentium cycle counter.
KIUse8254Tmr MACRO	hname,inst
	EXTRN	HookKI_&hname&_gettmr&inst&:NEAR
	;; 90h --> nop
	;; 0ffh, 15h, addr --> call contents of addr
	mov	eax, 15ff90h
	mov	DWORD PTR HookKI_&hname&_gettmr&inst&, eax
	lea	eax, DHF.DosHlpTmr32QueryTime  ; get address (assuming FLAT)
	mov	DWORD PTR HookKI_&hname&_gettmr&inst& + 3, eax
ENDM

KIAccumulate  MACRO  laststate
	db	05h,0,0,0,0		; ADD EAX, 0
	db	0fh, 31h		; RDTSC, current timestamp
	sub	eax, _KI_statechg_lts	; timer diff from last state chg
	sbb	edx, _KI_statechg_hts
ifnb <laststate>
	add	_KI_&laststate&_ltime, eax
	adc	_KI_&laststate&_htime, edx
else
	add	[ebx], eax		; accumulate last state
	adc	[ebx+4], edx		;
endif
	add	_KI_statechg_lts, eax	; set state change timestamp
	adc	_KI_statechg_hts, edx
ENDM


;;; Goto_Idle hook macro
;;; state change:	busy --> idle
HookKI_goidle  MACRO
	public  HookKI_goidle_entry
	public	HookKI_goidle_gettmr
	public  HookKI_goidle_exit
HookKI_goidle_entry:
	;; KI hooks should be off initially.  They will be turned at the
	;; system initialization time when it is safe to do so.
	jmp	short HookKI_goidle_exit
	; pushfd
	; cli
	SaveReg <eax, edx>

HookKI_goidle_gettmr:
	KIAccumulate  busy	; last state was busy

	mov	_KI_proc_state, KI_STATE_IDLE
	RestoreReg <edx, eax>
	; enable interrupt and restore flags
	popfd
HookKI_goidle_exit:
ENDM


;;; Goto_Busy hook macro
;;; state change:	idle --> busy
HookKI_gobusy  MACRO
	public  HookKI_gobusy_entry
	public	HookKI_gobusy_gettmr
	public  HookKI_gobusy_exit
HookKI_gobusy_entry:
	;; KI hooks should be off initially.  They will be turned at the
	;; system initialization time when it is safe to do so.
	jmp	short HookKI_gobusy_exit
	; pushfd
	; cli
	SaveReg <eax, edx>

HookKI_gobusy_gettmr:
	KIAccumulate  idle	; last state was idle

	mov	_KI_proc_state, KI_STATE_BUSY
	RestoreReg <edx, eax>
	; enable interrupt and restore flags
	popfd
HookKI_gobusy_exit:
ENDM


;;; Entering Interrupt handling hook body
HookKI_intr_begin  MACRO  inst
	public  HookKI_intr_begin_entry&inst&
	public	HookKI_intr_begin_gettmr&inst&
	public  HookKI_intr_begin_exit&inst&
HookKI_intr_begin_entry&inst&:
	;; KI hooks should be off initially.  They will be turned at the
	;; system initialization time when it is safe to do so.
	jmp	short HookKI_intr_begin_exit&inst&
	; pushfd
	; cli
	SaveReg <eax, ebx, edx>

	lea	ebx, _KI_idle_ltime	; ebx = addres of idle counters
	mov	eax, _KI_proc_state
	and	eax, 0ffh
	add	ebx, eax		; ebx = addres of the counters
HookKI_intr_begin_gettmr&inst&:
	KIAccumulate			;       of the last state     

	shl	_KI_proc_state, 8	; save last state
	or	_KI_proc_state, KI_STATE_INTR
	RestoreReg <edx, ebx, eax>
	; restore interrupt and flags
	popfd
HookKI_intr_begin_exit&inst&:
ENDM


;;; Leave Interrupt handling hook body
HookKI_intr_end  MACRO  inst
	public  HookKI_intr_end_entry&inst&
	public	HookKI_intr_end_gettmr&inst&
	public  HookKI_intr_end_exit&inst&
HookKI_intr_end_entry&inst&:
	;; KI hooks should be off initially.  They will be turned at the
	;; system initialization time when it is safe to do so.
	jmp	short HookKI_intr_end_exit&inst&
	; pushfd
	; cli
	SaveReg <eax, edx>

HookKI_intr_end_gettmr&inst&:
	KIAccumulate	intr		; interrupt time

	shr	_KI_proc_state, 8
	RestoreReg <edx, eax>
	; restore interrupt and flags
	popfd
HookKI_intr_end_exit&inst&:
ENDM
