.title IDLE_LED Display idle time on uVAX II rear panel .ident "V1.1" ; ; This little ditty displays the idle time on the KA630 panel insert LED ; display by diddling the Boot & Diagnostic Register located at physical ; address ^x20080000. This is done from nonpaged pool using a repeating ; system subroutine TQE to run it at one second intervals. The program ; does not require a process slot after loading the into pool. ; ; Accessing the BDR is done by requesting a system page table entry and ; mapping it onto the BDR page. ; ; This has only been tested on the KA630 (MicroVAX II). It may work with ; other KA6xx processors if they use the same BDR format. On the other ; hand, it may crash other processors. It also does kernel stuff. You've ; been warned. I'd like to hear of mods to make it work on other systems. ; ; Privileges required: CMKRNL. ; ; Don Stokes , 15 January 1994. ; This program is in the public domain. No warranties expressed or implied. ; ; V1.1 15/1/94/dcs Coalesce code & TQE into one pool block. Make TQE ; a template in the loaded code, just fill in fields ; that have to be calculated at run time. ; .library "SYS$LIBRARY:LIB.MLB" .link "SYS$SYSTEM:SYS.STB"/selective_search $PRTDEF ; Page protections $PTEDEF ; Page Table Entry constants/offsets $TQEDEF ; Timer Queue Entry constants/offsets $IPLDEF ; Interrupt Priority Levels $CPUDEF ; CPU database offsets $DYNDEF ; Dynamic structure type codes PHY_BDR = ^x20080000 ; Phy address of Boot & Diagnostic Reg BDR_PTE = < PTE$M_VALID - ! - ! PTE$M_WINDOW - ! > ; PTE to map BDR, valid, window, KW .psect IDLE_LED_RE, long,exe,shr,nowrt ; ; Code to get idle time and place in LED display, run from TQE in nonpaged ; pool at IPL$_TIMER at one second intervals. ; This is aggressively non-SMP code and only measures idle time on CPU 0. ; Idle time is converted to a busy time fingure in the range 0..9. ; On entry: R3 VA of mapped BDR (from TQE$L_FR3) ; R4 Last value of CPU$L_NULLCPU (from TQE$L_FR4) ; R5 address of TQE ; On exit: TQE$L_FR4 Current value of CPU$L_NULLCPU ; R5 Must contain address of TQE ; R0 Trashed ; This is preceeded by a template TQE; the template will be filled out and ; the whole mess hoisted into nonpaged pool. ; .psect IDLE_LED_RW, long,noexe,noshr,wrt krnl_base: ; TQE template .blkq ; TQFL/TQBL filled by EXE$INSTIMQ .blkw ; SIZE Size of whole block .byte DYN$C_TQE ; TYPE TQE .byte TQE$C_SSREPT ; RQTYPE Repeating subroutine .blkl ; FPC pool addr of krnl_entry .blkl ; FR3 VA of mapped BDR .long 0 ; FR4 last null CPU .blkq ; TIME filled by EXE$INSTIMQ .quad 10000000 ; DELTA one second .long 0 ; EFN/RMOD not used .long 0 ; RQPID not used .long 0 ; CPUTIM not used krnl_entry = . - krnl_base ; Code movl g^SMP$GL_CPU_DATA, R0 ; R0=address of CPU 0's counters movl CPU$L_NULLCPU(R0), R0 ; R0=absolute idle time on CPU 0 movl R0, TQE$L_FR4(R5) ; save absolute idle time subl R4, R0 ; R0=delta idle time, 10ms ticks divl #10, R0 ; R0=delta idle time,100ms ticks subl3 R0, #9, R0 ; R0=busy time, 0..9 bgeq 1$ ; Underflow? clrl R0 ; Correct underflow 1$: movw R0, (R3) ; Place in BDR rsb ; Done krnl_size = . - krnl_base .psect IDLE_LED_RE, long,exe,shr,nowrt ; ; Entry point -- call kernel mode stuff. ; .entry idle_led, ^M<> $CMKRNL_S routin=install_krnl ; Who needs user-mode code? ret ; ; Kernel mode code, process context. Map page, load TQE into pool, insert it. ; .entry install_krnl, ^M ; ; Map page onto BDR ; movl #1, R2 ; R2=PTE count jsb g^LDR$ALLOC_PT ; Get PTE blbc R0, 99$ ; OK? movl #BDR_PTE, (R1) ; Map page, R1=PTE adr, R2=count subl3 g^LDR$GL_SPTBASE, R1, R7 ; R7=PTE number*4 ashl #7, R7, R7 ; R7=offset to VA in sys space bisl #^x80000000, R7 ; R7=absolute VA of mapped BDR ; ; Allocate some nonpaged pool and put a TQE and code into it ; Fill out TQE size, FPC & FR3 fields. ; Copy filled out TQE and code into allocated block. ; movl #krnl_size, R1 jsb g^EXE$ALONONPAGED ; Allocate some nonpaged pool blbc R0, 99$ ; R2=pool address, R1=length movw R1, krnl_base+TQE$W_SIZE ; Set size of allocated TQE/code movab krnl_entry(R2), - krnl_base+TQE$L_FPC ; routine address movl R7, krnl_base+TQE$L_FR3 ; Use BDR addr as R3 in TQE movl R2, R6 ; R6=pool address movc3 #krnl_size, - krnl_base, (R6) ; Copy code into pool ; ; Now queue the TQE. This is done at IPL$_TIMER to protect against accidents. ; Note that this uses poor man's lockdown; this isn't intended for SMP systems! ; movl R6, R5 ; EXE$INSTIMQ wants TQE in R5 dsbint ipl=10$, - environ=uniprocessor ; Shields up! movq g^EXE$GQ_SYSTIME, R0 ; TQE will fire on next tick jsb g^EXE$INSTIMQ ; insert it into queue enbint ; Shields down movl #SS$_NORMAL, R0 99$: ret ; Errors come here 10$: .long IPL$_TIMER ; Poor man's lockdown... .end idle_led