home *** CD-ROM | disk | FTP | other *** search
/ Win 3.11 Apps / win311aps.iso / DOSIDLE / DOSIDLE.ASM next >
Assembly Source File  |  1998-05-07  |  56KB  |  1,522 lines

  1. ;                           ▄┌═════════════════┐▄                            ;
  2. ;                        ─══╣│ CPUidle for DOS │╠══─                         ;
  3. ;                           ▀└─────────────────┘▀                            ;
  4.  
  5.  
  6. ;[KERNEL CHARACTERISTICS]
  7. ; Kernel name:          CPUidle for DOS.
  8. ; Kernel version:       V2.10 [Build 0077]
  9. ; Programming stage:    Working version, Under development.
  10. ; Last modified:        1998 May 07.
  11.  
  12. ;[NOTES]
  13. ; Ralphs intlist -> more idle possibilities.
  14.  
  15.  
  16.  
  17. ;╔══════════════════════════════════════════════════════════════════════════╗;
  18. ;║ ▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓ RESIDENT PART OF PROGRAM ▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓ ║;
  19. ;╚══════════════════════════════════════════════════════════════════════════╝;
  20. ;────────────────────────────────────────────────────────────────────────────;
  21. ;░░░░░░░░░░▒▒▒▒▒▒▒▒▒▒ GLOBAL CODE & DATA FOR ALL HANDLERS ▒▒▒▒▒▒▒▒▒▒░░░░░░░░░;
  22. ;────────────────────────────────────────────────────────────────────────────;
  23.  
  24. ideal                                   ; Yep, this prog is TASM 4.0 coded!
  25. include "_stddata.ah"
  26. include "_tsrres.ah"
  27. include "_dcon.ah"
  28.  
  29.  
  30. ;════════════════════════════════════════════════════════════════════════════;
  31.  
  32.  
  33. Struct  qk_item
  34.         prog    db 12 dup (0), 0        ; Name of the child process.
  35.         hooknum db 0                    ; Number of FN hooks.
  36.         execnum dw 0                    ; "PID number" of child.
  37. Ends
  38.  
  39. Struct  qk_hook
  40.         fnaddr  dw 0                    ; Address of FN to hook.
  41.         newaddr dw 0                    ; New address of the FN.
  42.         oldaddr dw 0                    ; Old address of the FN.
  43. Ends
  44.  
  45.  
  46. ;════════════════════════════════════════════════════════════════════════════;
  47.  
  48.  
  49. MODE_OPTIMIZE   = 01h                   ; Set if CPU optimization selected.
  50. MODE_HLT        = 02h                   ; Set if normal HLT method selected.
  51. MODE_APM        = 04h                   ; Set if APM cooling method selected.
  52. MODE_NOFORCE    = 08h                   ; Set if any FORCE MODE is disabled.
  53. MODE_WFORCE     = 10h                   ; Set if WEAK FORCE strategy selected.
  54. MODE_SFORCE     = 20h                   ; Set if STRONG FORCE strategy selected.
  55.  
  56. IRQ_00          = 01h                   ;
  57. IRQ_01          = 02h                   ;
  58. IRQ_02          = 04h                   ;
  59. IRQ_03          = 08h                   ;
  60. IRQ_04          = 10h                   ;
  61. IRQ_05          = 20h                   ; Flag set if that specific IRQ was
  62. IRQ_06          = 40h                   ; invoked. Should later be cleared by
  63. IRQ_07          = 80h                   ; kernel...
  64.  
  65. INT_XXH_FORCE   = 300                   ; # of calls to FN before forced HLT. 
  66.  
  67.  
  68. ;════════════════════════════════════════════════════════════════════════════;
  69.  
  70.  
  71. RESIDENTDATA begin
  72.  
  73. Align 4
  74. int_xxh_fcount  dd 0                    ;  # int xxh FN(x) called repeatedly.
  75.  
  76. mode_flags      db MODE_SFORCE          ; Config flags for program startup.
  77. irq_flags       db 0                    ; IRQ flags for kernel.
  78.  
  79. quirk_table     qk_item <"NC.EXE", 1, 0>
  80.                  qk_hook <int_21h_fntable + 2ch * 2, int_xxh_forcehlt, int_xxh_zerocount>
  81.                 qk_item <"SCANDISK.EXE", 1, 0>
  82.                  qk_hook <int_21h_fntable + 0bh * 2, int_xxh_zerocount, int_xxh_forcehlt>
  83.                 QK_ITEMS = 2
  84.  
  85. exec_calls      dw 200                  ; Count of DOS FN 4bh calls.
  86. child_name      db 13 dup (0)           ; Name of the child to be executed.
  87.  
  88. RESIDENTDATA end
  89.  
  90.  
  91. ;════════════════════════════════════════════════════════════════════════════;
  92.  
  93.  
  94. RESIDENTCODE begin
  95.  
  96. Proc    _str_cmp                        ; NOTE: Copied from _string.h!!
  97.         push ax cx si di
  98.  
  99.         mov cx,DEF_STR_LEN              ; CX = default string length.
  100. @@cmp:  mov al,[ds:si]                  ; Read char from string #1.
  101.         cmp al,[es:di]                  ; Char (#1) == char (#2)?
  102.         jne short @@done                ; Nope, strings can't be equal.
  103.  
  104.         test al,al                      ; Done (char (#1) = char (#2) = 0)?
  105.         jz short @@done                 ; Yes, string are equal.
  106.  
  107.         inc si                          ;
  108.         inc di                          ;
  109.         loop @@cmp                      ; Continue.
  110.  
  111. @@done: pop di si cx ax
  112.         ret
  113. Endp
  114.  
  115.  
  116. ;----------------------------------------------------------------------------;
  117.  
  118. Proc    int_xxh_forcehlt
  119.         inc [int_xxh_fcount]                    ; Increase force counter.
  120.         cmp [int_xxh_fcount],INT_XXH_FORCE      ; Over the minimum?
  121.         jb short @@done                         ; Nah, don't HLT yet.
  122.  
  123.         mov [irq_flags],0               ; Clear IRQ flags.
  124.         sti                             ; Enable IRQs for following HLT.
  125.  
  126.         test [mode_flags],MODE_APM      ; APM usage requested?
  127.         jnz short @@apm                 ; Yes.
  128.  
  129.         ;-  -  -  -  -  -  -  -  -  -  -;
  130. @@std:  test [mode_flags],MODE_SFORCE   ; Running under STRONG FORCE mode?
  131.         jnz short @@stds                ; Yes.
  132.  
  133. @@stdw: hlt                             ; Enter power saving mode.
  134.         ret                             ; Fast exit.
  135.  
  136. @@stds: and [irq_flags],not IRQ_00      ; Clear IRQ0 occurred flag.
  137.     hlt                             ; Enter power saving mode.
  138.  
  139.         cmp [irq_flags],IRQ_00          ; Was it IRQ0 (timer) ONLY?!
  140.         je @@stds                       ; Yes, go back HLTing.
  141.         ret                             ; Fast exit.
  142.         ;-  -  -  -  -  -  -  -  -  -  -;
  143.  
  144.         ;-  -  -  -  -  -  -  -  -  -  -;
  145. @@apm:  test [mode_flags],MODE_SFORCE   ; Running under STRONG FORCE mode?
  146.         jnz short @@apms                ; Yes.
  147.  
  148. @@apmw: mov ax,5305h                    ;
  149.         pushf                           ;
  150.         call [dword old_int_15h]        ; Call APM FN to put the CPU idle.
  151.         ret
  152.  
  153. @@apms: and [irq_flags],not IRQ_00      ; Clear IRQ0 occurred flag.
  154.         mov ax,5305h                    ;
  155.         pushf                           ;
  156.         call [dword old_int_15h]        ; Call APM FN to put the CPU idle.
  157.  
  158.         cmp [irq_flags],IRQ_00          ; Was it IRQ0 (timer) ONLY?!
  159.         je @@apms                       ; Yes, go back HLTing.
  160.         ;-  -  -  -  -  -  -  -  -  -  -;
  161. @@done: ret
  162. Endp
  163.  
  164. ;- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ;
  165.  
  166. Proc    int_xxh_zerocount               ; Zero ALL FORCE counters.
  167.         mov [int_xxh_fcount],0          ; Zero int xxh force counter.
  168.         ret
  169. Endp
  170.  
  171. ;- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ;
  172.  
  173. Proc    int_xxh_skip                    ; Skip ALL FORCE counter updates.
  174.         ret
  175. Endp
  176.  
  177. RESIDENTCODE end
  178.  
  179.  
  180.  
  181. ;────────────────────────────────────────────────────────────────────────────;
  182. ;░░░░░░░░░░░░░░░▒▒▒▒▒▒▒▒▒▒▒▒▒▒ INT 21H HANDLER ▒▒▒▒▒▒▒▒▒▒▒▒▒▒░░░░░░░░░░░░░░░░;
  183. ;────────────────────────────────────────────────────────────────────────────;
  184.  
  185. INT_21H_TOPFN   = 4ch                   ; Highest FN that is handled.
  186.  
  187.  
  188. ;════════════════════════════════════════════════════════════════════════════;
  189.  
  190.  
  191. RESIDENTDATA begin
  192.  
  193. Align 4
  194. old_int_21h     rmdw <0, 0>
  195.  
  196. int_21h_fntable dw int_xxh_zerocount    ; FN 00h: Terminate.
  197.                 dw int_21h_normalhlt    ; FN 01h: Keyboard input.
  198.                 dw int_xxh_zerocount    ; FN 02h: Display char.
  199.                 dw int_xxh_skip         ; FN 03h: Auxiliary input.
  200.                 dw int_xxh_zerocount    ; FN 04h: Auxiliary output.
  201.                 dw int_xxh_zerocount    ; FN 05h: Printer output.
  202.                 dw int_21h_fn06h        ; FN 06h: Console I/O.
  203.                 dw int_21h_normalhlt    ; FN 07h: No echo unfiltered input.
  204.                 dw int_21h_normalhlt    ; FN 08h: No echo input.
  205.                 dw int_xxh_zerocount    ; FN 09h: Display string.
  206.                 dw int_xxh_skip         ; FN 0ah: Buffered input.
  207.                 dw int_xxh_forcehlt     ; FN 0bh: "Keypressed?"
  208.                 dw int_xxh_skip         ; FN 0ch: Clear buffer and input.
  209.                 dw 24h dup (int_xxh_zerocount)  ; FNs 0dh - 30h.
  210.                 dw int_21h_fn31h        ; FN 31h: Terminate and Stay Resident.
  211.                 dw 19h dup (int_xxh_zerocount)  ; FNs 32h - 4ah.
  212.                 dw int_21h_fn4bh        ; FN 4bh: Execute child process.
  213.                 dw int_21h_fn4ch        ; FN 4ch: Terminate child process.
  214.  
  215. RESIDENTDATA end
  216.  
  217.  
  218. ;════════════════════════════════════════════════════════════════════════════;
  219.  
  220.  
  221. RESIDENTCODE begin
  222.  
  223. Proc    int_21h_fn06h                   ; DOS FN: Console I/O.
  224.         cmp dl,0ffh                     ; "Keypressed?" function requested?
  225.         jne short @@done                ; No.
  226.  
  227.         jmp [int_21h_fntable + 0bh * 2] ; Force HLT (as FN 0bh does it).
  228. @@done: ret
  229. Endp
  230.  
  231. ;- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ;
  232.  
  233. Proc    int_21h_fn31h                   ; DOS FN: Terminate and Stay Resident.
  234.         jmp int_21h_fn4ch               ; Same as standard exit...
  235. Endp
  236.  
  237. ;- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ;
  238.  
  239. Proc    int_21h_fn4bh                   ; DOS FN: Execute child process.
  240.         pusha
  241.         push es                         ;
  242.         mov bp,sp                       ; BP = ptr to entry DS on stack.
  243.  
  244.         inc [exec_calls]                ; Increase count of exec calls.
  245.  
  246.         test al,al                      ; Load and execute child?
  247.         jnz short @@done                ; No, no work for us.
  248.  
  249.         mov ax,[ss:bp + 2 + 16 + 2]     ; Get DS from stack.
  250.         mov es,ax                       ; 
  251.         mov di,dx                       ; ES:DI = caller's DS:DX = child name.
  252.  
  253.         ;-  -  -  -  -  -  -  -  -  -  -;
  254.         lea si,[child_name]             ; DS:SI = target buffer for child name.
  255.         xor bx,bx                       ; BX = index of char at [DS:SI].
  256.  
  257. @@read: mov al,[es:di]                  ; Get char of child name in int 21h.
  258.         mov [ds:si + bx],al             ; Save it to our buffer.
  259.  
  260.         cmp al,':'                      ; Was it a DRIVE specifier?
  261.         je short @@kill                 ; Yes.
  262.  
  263.         cmp al,'\'                      ; Was it a PATH separator?
  264.         jne short @@next                ; No.
  265.  
  266. @@kill: mov bx,-1                       ; Restart savig to buffer...
  267.  
  268. @@next: inc di                          ;
  269.         inc bx                          ; Advance index pointers.
  270.         test al,al                      ; At end of ASCIIZ filename?
  271.         jnz @@read                      ; No.
  272.         ;-  -  -  -  -  -  -  -  -  -  -;
  273.  
  274.         ;-  -  -  -  -  -  -  -  -  -  -;
  275.         lea bx,[quirk_table]            ; BX = ptr to table of quirky programs.
  276.         mov cx,QK_ITEMS                 ; CX = number of entries in table.
  277.         lea di,[child_name]             ;
  278.         mov ax,ds                       ;
  279.         mov es,ax                       ; ES:DI = ptr to ASCIIZ name of child.
  280.  
  281. @@find: lea si,[(qk_item bx).prog]      ; SI = ptr to quirky child name.
  282.         call _str_cmp                   ; Is this child being executed?
  283.         je short @@set                  ; Yes, handle it.
  284.  
  285.         mov al,[(qk_item bx).hooknum]   ; AL = number of FN hooks.
  286.         mov ah,size qk_hook             ; AH = size of one FN hook.
  287.         mul ah                          ; AX = value to increment BX with.
  288.  
  289.         add bx,ax                       ;
  290.         add bx,size qk_item             ;
  291.         loop @@find                     ; Continue.
  292.         jmp short @@done                ; Child is NOT a quirky program, done.
  293.         ;-  -  -  -  -  -  -  -  -  -  -;
  294.  
  295.         ;-  -  -  -  -  -  -  -  -  -  -;
  296. @@set:  mov ax,[exec_calls]             ;
  297.         mov [(qk_item bx).execnum],ax   ; Save "PID" of this quirky program.
  298.  
  299.         xor ch,ch                       ;
  300.         mov cl,[(qk_item bx).hooknum]   ; CX = number of hooks to install.
  301.         add bx,size qk_item             ; BX = ptr to first hook data.
  302.  
  303.         test cl,cl                      ; No hooks needed?
  304.         jz short @@done                 ; Yes, crazy but quit...
  305.  
  306. @@hook: mov si,[(qk_hook bx).fnaddr]    ; SI = address of FN to hook.
  307.         mov ax,[ds:si]                  ; Get old FN handler.
  308.         mov [(qk_hook bx).oldaddr],ax   ; Save it.
  309.  
  310.         mov ax,[(qk_hook bx).newaddr]   ; Get new address for FN handler.
  311.         mov [ds:si],ax                  ; Hook FN.
  312.  
  313.         add bx,size qk_hook             ;
  314.         loop @@hook                     ; Continue.
  315.         ;-  -  -  -  -  -  -  -  -  -  -;
  316.  
  317. @@done: pop es
  318.         popa
  319.         ret
  320. Endp
  321.  
  322. ;- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ;
  323.  
  324. Proc    int_21h_fn4ch                   ; DOS FN: Terminate child process.
  325.         pusha
  326.         lea bx,[quirk_table]            ; BX = ptr to table of quirky programs.
  327.         mov cx,QK_ITEMS                 ; CX = number of entries in table.
  328.  
  329.         ;-  -  -  -  -  -  -  -  -  -  -;
  330. @@find: mov ax,[(qk_item bx).execnum]   ; Get "PID" of saved program.
  331.         cmp ax,[exec_calls]             ; Is it this program?
  332.         je short @@set                  ; Yes, handle it.
  333.  
  334.         mov al,[(qk_item bx).hooknum]   ; AL = number of FN hooks.
  335.         mov ah,size qk_hook             ; AH = size of one FN hook.
  336.         mul ah                          ; AX = value to increment BX with.
  337.  
  338.         add bx,ax                       ;
  339.         add bx,size qk_item             ;
  340.         loop @@find                     ; Continue.
  341.         jmp short @@done                ; Finish, program wasn't found.
  342.         ;-  -  -  -  -  -  -  -  -  -  -;
  343.  
  344.         ;-  -  -  -  -  -  -  -  -  -  -;
  345. @@set:  xor ch,ch                       ;
  346.         mov cl,[(qk_item bx).hooknum]   ; CX = number of hooks to deinstall.
  347.         add bx,size qk_item             ; BX = ptr to first hook data.
  348.  
  349.         test cl,cl                      ; No hooks needed?
  350.         jz short @@done                 ; Yes, crazy but quit...
  351.  
  352. @@unhk: mov si,[(qk_hook bx).fnaddr]    ; SI = address of FN to unhook.
  353.         mov ax,[(qk_hook bx).oldaddr]   ; Get old FN handler.
  354.         mov [ds:si],ax                  ; Restore original handler.
  355.  
  356.         add bx,size qk_hook             ;
  357.         loop @@unhk                     ; Continue.
  358.         ;-  -  -  -  -  -  -  -  -  -  -;
  359.  
  360. @@done: dec [exec_calls]
  361.         popa
  362.         ret
  363. Endp
  364.  
  365.  
  366. ;----------------------------------------------------------------------------;
  367.  
  368.  
  369. Proc    int_21h_normalhlt
  370.         sti                             ; Enable IRQs for following HLT.
  371.         mov ah,0bh                      ; Int 21h FN: "Keypressed?".
  372.  
  373.         test [mode_flags],MODE_APM      ; APM usage requested?
  374.         jnz short @@apml                ; Yes.
  375.  
  376. @@stdl: hlt                             ; Enter power saving mode.
  377.         pushf                           ;
  378.         call [dword old_int_21h]        ; Simulate int 21h without reentrancy.
  379.  
  380.         cmp al,0ffh                     ; Keystroke ready?
  381.         jne @@stdl                      ; No, continue HLTing.
  382.         jmp short @@done                ; Finish.
  383.  
  384. @@apml: mov ax,5305h                    ;
  385.         pushf                           ;
  386.         call [dword old_int_15h]        ; Call APM FN to put the CPU idle.
  387.  
  388.         mov ah,0bh                      ; Int 21h FN: "Keypressed?"
  389.         pushf                           ;
  390.         call [dword old_int_21h]        ; Simulate int 21h without reentrancy.
  391.  
  392.         cmp al,0ffh                     ; Keystroke ready?
  393.         jne @@apml                      ; No, continue HLTing.
  394. @@done: ret
  395. Endp
  396.  
  397.  
  398. ;----------------------------------------------------------------------------;
  399.  
  400.  
  401. Align 16
  402. Proc    int_21h_handler                 ; DOS functions handler.
  403.         push ax bx ds
  404.         mov bx,cs                       ;
  405.         mov ds,bx                       ; CODE = DATA.
  406.  
  407.         cmp ah,INT_21H_TOPFN            ; FN irrelevant for our handler?
  408.         ja short @@old                  ; Yes, zero force counter and chain.
  409.  
  410.         xor bh,bh                       ;
  411.         mov bl,ah                       ;
  412.         add bx,bx                       ; BX = index to int_21h_fntable.
  413.         add bx,offset int_21h_fntable   ; BX = offset of handler.
  414.  
  415.         call [word bx]                  ; Call the appropriate FN handler.
  416.         jmp short @@oldn                ; Chain without zeroing force count.
  417.  
  418. @@old:  mov [int_xxh_fcount],0          ; Zero int xxh force counter.
  419.  
  420. @@oldn: pop ds bx ax
  421.         jmp [dword cs:old_int_21h]      ; Chain to old interrupt handler.
  422. Endp
  423.  
  424. RESIDENTCODE end
  425.  
  426.  
  427.  
  428. ;────────────────────────────────────────────────────────────────────────────;
  429. ;░░░░░░░░░░░░░░░▒▒▒▒▒▒▒▒▒▒▒▒▒▒ INT 16H HANDLER ▒▒▒▒▒▒▒▒▒▒▒▒▒▒░░░░░░░░░░░░░░░░;
  430. ;────────────────────────────────────────────────────────────────────────────;
  431.  
  432. INT_16H_TOPFN   = 12h                   ; Highest FN that is handled.
  433.  
  434.  
  435. ;════════════════════════════════════════════════════════════════════════════;
  436.  
  437.  
  438. RESIDENTDATA begin
  439.  
  440. Align 4
  441. old_int_16h     rmdw <0, 0>
  442.  
  443. int_16h_fntable dw int_16h_normalhlt    ; FN 00h: Keyboard input.
  444.                 dw int_xxh_forcehlt     ; FN 01h: "Keypressed?".
  445.                 dw int_xxh_forcehlt     ; FN 02h: "SHIFT Keypressed?".
  446.                 dw 0dh dup (int_xxh_zerocount)  ; FNs 03h - 09h.
  447.                 dw int_16h_normalhlt    ; FN 10h: Keyboard input (101-keys).
  448.                 dw int_xxh_forcehlt     ; FN 11h: "Keypressed?" (101-keys).
  449.                 dw int_xxh_forcehlt     ; FN 12h: "SHIFT Keypressed?" (101).
  450.  
  451. RESIDENTDATA end
  452.  
  453.  
  454. ;════════════════════════════════════════════════════════════════════════════;
  455.  
  456.  
  457. RESIDENTCODE begin
  458.  
  459. Proc    int_16h_normalhlt
  460.     inc ah                          ; Int 16h FN: Is keystroke ready?
  461.         mov bh,ah                       ; Save AH (FN number).
  462.     sti                             ; Enable IRQs for following HLT.
  463.  
  464.         test [mode_flags],MODE_APM      ; APM usage requested?
  465.         jnz short @@apml                ; Yes.
  466.  
  467. @@stdl: pushf                           ;
  468.         call [dword old_int_16h]        ; Simulate int 16h without reentrancy.
  469.         jnz short @@done                ; If ZF == 0 then key is ready.
  470.  
  471.         hlt                             ; Enter power saving mode.
  472.  
  473.         mov ah,bh                       ; Restore saved AH (FN number).
  474.         jmp @@stdl
  475.  
  476. @@apml: pushf                           ;
  477.         call [dword old_int_16h]        ; Simulate int 16h without reentrancy.
  478.         jnz short @@done                ; If ZF == 0 then key is ready.
  479.  
  480.         mov ax,5305h                    ;
  481.         pushf                           ;
  482.         call [dword old_int_15h]        ; Call APM FN to put the CPU idle.
  483.  
  484.         mov ah,bh                       ; Restore saved AH (FN number).
  485.         jmp @@apml                      ; No, continue HLTing.
  486. @@done: ret
  487. Endp
  488.  
  489.  
  490. ;----------------------------------------------------------------------------;
  491.  
  492.  
  493. Align 16
  494. Proc    int_16h_handler                 ; BIOS keyboard functions handler.
  495.         push ax bx ds
  496.         mov bx,cs                       ;
  497.         mov ds,bx                       ; CODE = DATA.
  498.  
  499.         cmp ah,INT_16H_TOPFN            ; FN irrelevant for our handler?
  500.         ja short @@old                  ; Yes, zero force counter and chain.
  501.  
  502.         xor bh,bh                       ;
  503.         mov bl,ah                       ;
  504.         add bx,bx                       ; BX = index to int_16h_fntable.
  505.         add bx,offset int_16h_fntable   ; BX = offset of handler.
  506.  
  507.         call [word bx]                  ; Call the appropriate FN handler.
  508.         jmp short @@oldn                ; Chain without zeroing force count.
  509.  
  510. @@old:  mov [int_xxh_fcount],0          ; Zero int xxh force counter.
  511.  
  512. @@oldn: pop ds bx ax
  513.         jmp [dword cs:old_int_16h]      ; Chain to old interrupt handler.
  514. Endp
  515.  
  516. RESIDENTCODE end
  517.  
  518.  
  519.  
  520. ;────────────────────────────────────────────────────────────────────────────;
  521. ;░░░░░░░░░░░░░░░▒▒▒▒▒▒▒▒▒▒▒▒▒▒ INT 2FH HANDLER ▒▒▒▒▒▒▒▒▒▒▒▒▒▒░░░░░░░░░░░░░░░░;
  522. ;────────────────────────────────────────────────────────────────────────────;
  523.  
  524. INT_2FH_TOPFN   = 0ffffh                ; Highest FN that is handled.
  525.  
  526.  
  527. ;════════════════════════════════════════════════════════════════════════════;
  528.  
  529.  
  530. RESIDENTDATA begin
  531.  
  532. Align 4
  533. old_int_2fh     rmdw <0, 0>
  534.  
  535. RESIDENTDATA end
  536.  
  537.  
  538. ;════════════════════════════════════════════════════════════════════════════;
  539.  
  540.  
  541. RESIDENTCODE begin
  542.  
  543. Align 16
  544. Proc    int_2fh_handler
  545.         push dx ds
  546.         mov dx,cs                       ;
  547.         mov ds,dx                       ; CODE = DATA.
  548.         
  549.         cmp ax,1680h                    ; DPMI release time slice?
  550.         je short @@dpmi                 ; Yes.
  551.  
  552.         cmp ax,1607                     ; Windows VMPoll Idle callout?
  553.         jne short @@old                 ; No, exit.
  554.  
  555. @@vmpl: cmp bx,0018h                    ; Is it the VMPoll VxD ID number?
  556.         jne short @@old                 ; No, exit.
  557.  
  558.         test cx,cx                      ; Is it the VMPoll driver?
  559.         jnz short @@old                 ; No, exit.
  560.  
  561. @@dpmi: call int_xxh_forcehlt           ; Enter power saving mode.
  562.         jmp short @@oldn                ; Chain without zeroing force count.
  563.  
  564. @@old:  mov [int_xxh_fcount],0          ; Zero int xxh force counter.
  565.  
  566. @@oldn: pop ds dx
  567.         jmp [dword cs:old_int_2fh]      ; Chain to old interrupt handler.
  568. Endp
  569.  
  570. RESIDENTCODE end
  571.  
  572.  
  573.  
  574. ;────────────────────────────────────────────────────────────────────────────;
  575. ;░░░░░░░░░░░░░░░▒▒▒▒▒▒▒▒▒▒▒▒▒▒ INT 14H HANDLER ▒▒▒▒▒▒▒▒▒▒▒▒▒▒░░░░░░░░░░░░░░░░;
  576. ;────────────────────────────────────────────────────────────────────────────;
  577.  
  578. INT_14H_TOPFN   = 03h                   ; Highest FN that is handled.
  579.  
  580.  
  581. ;════════════════════════════════════════════════════════════════════════════;
  582.  
  583.  
  584. RESIDENTDATA begin
  585.  
  586. Align 4
  587. old_int_14h     rmdw <0, 0>
  588.  
  589. int_14h_fntable dw int_xxh_zerocount    ; FN 00h: Init COM port.
  590.                 dw int_xxh_zerocount    ; FN 01h: Send char to COM port.
  591.                 dw int_14h_normalhlt    ; FN 02h: Read char from COM port.
  592.                 dw int_xxh_forcehlt     ; FN 03h: "Char ready?"
  593.  
  594. RESIDENTDATA end
  595.  
  596.  
  597. ;════════════════════════════════════════════════════════════════════════════;
  598.  
  599.  
  600. RESIDENTCODE begin
  601.  
  602. Proc    int_14h_normalhlt
  603.     sti                             ; Enable IRQs for following HLT.
  604.  
  605.         test [mode_flags],MODE_APM      ; APM usage requested?
  606.         jnz short @@apml                ; Yes.
  607.  
  608. @@stdl: hlt                             ; Enter power saving mode.
  609.         mov ah,03h                      ; Int 14h FN: Get serial port status.
  610.         pushf                           ;
  611.         call [dword old_int_14h]        ; Simulate int 14h without reentrancy.
  612.  
  613.         test ah,1                       ; Is data ready?
  614.         jz @@stdl                       ; No, continue loop.
  615.         jmp short @@done                ; Finish.
  616.  
  617. @@apml: mov ax,5305h                    ;
  618.         pushf                           ;
  619.         call [dword old_int_15h]        ; Call APM FN to put the CPU idle.
  620.  
  621.         mov ah,03h                      ; Int 14h FN: Get serial port status.
  622.         pushf                           ;
  623.         call [dword old_int_14h]        ; Simulate int 14h without reentrancy.
  624.  
  625.         test ah,1                       ; Is data ready?
  626.         jz @@apml                       ; No, continue loop.
  627. @@done: ret
  628. Endp
  629.  
  630.  
  631. ;----------------------------------------------------------------------------;
  632.  
  633.  
  634. Align 16
  635. Proc    int_14h_handler                 ; BIOS serial I/O handler.
  636.         push ax bx ds
  637.         mov bx,cs                       ;
  638.         mov ds,bx                       ; CODE = DATA.
  639.  
  640.         cmp ah,INT_14H_TOPFN            ; FN irrelevant for our handler?
  641.         ja short @@old                  ; Yes, zero force counter and chain.
  642.  
  643.         xor bh,bh                       ;
  644.         mov bl,ah                       ;
  645.         add bx,bx                       ; BX = index to int_14h_fntable.
  646.         add bx,offset int_14h_fntable   ; BX = offset of handler.
  647.  
  648.         call [word bx]                  ; Call the appropriate FN handler.
  649.         jmp short @@oldn                ; Chain without zeroing force count.
  650.  
  651. @@old:  mov [int_xxh_fcount],0          ; Zero int xxh force counter.
  652.  
  653. @@oldn: pop ds bx ax
  654.         jmp [dword cs:old_int_14h]      ; Chain to old interrupt handler.
  655. Endp
  656.  
  657. RESIDENTCODE end
  658.  
  659.  
  660.  
  661. ;────────────────────────────────────────────────────────────────────────────;
  662. ;░░░░░░░░░░░░░░░▒▒▒▒▒▒▒▒▒▒▒▒▒▒ INT 1xH HANDLER ▒▒▒▒▒▒▒▒▒▒▒▒▒▒░░░░░░░░░░░░░░░░;
  663. ;────────────────────────────────────────────────────────────────────────────;
  664.  
  665. RESIDENTDATA begin
  666.  
  667. Align 4
  668. old_int_10h     rmdw <0, 0>             ;
  669. old_int_15h     rmdw <0, 0>             ; Original vector values.
  670.  
  671. RESIDENTDATA end
  672.  
  673.  
  674. ;════════════════════════════════════════════════════════════════════════════;
  675.  
  676.  
  677. RESIDENTCODE begin
  678.  
  679. Proc    int_10h_handler                 ; BIOS video functions handler.
  680.         mov [cs:int_xxh_fcount],0       ; Zero int xxh force counter.
  681.         jmp [dword cs:old_int_10h]      ; Chain to old interrupt handler.
  682. Endp
  683.  
  684.  
  685. ;----------------------------------------------------------------------------;
  686.  
  687.  
  688. Proc    int_15h_handler                 ; BIOS AT Services handler.
  689.         cmp ax,5305h                    ; APM function: CPU idle called?
  690.         je short @@old                  ; No.
  691.  
  692.         mov [cs:int_xxh_fcount],0       ; Zero int xxh force counter.
  693.  
  694. @@old:  jmp [dword cs:old_int_15h]      ; Chain to old interrupt handler.
  695. Endp
  696.  
  697. RESIDENTCODE end
  698.  
  699.  
  700.  
  701. ;────────────────────────────────────────────────────────────────────────────;
  702. ;░░░░░░░░░░░░░░░░▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒ IRQ HANDLERS ▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒░░░░░░░░░░░░░░░░;
  703. ;────────────────────────────────────────────────────────────────────────────;
  704.  
  705. RESIDENTDATA begin
  706.  
  707. Align 4
  708. old_masterirqs  rmdw 8 dup (<0, 0>)     ; Original handlers of the hooked IRQs.
  709.  
  710. new_masterirqs  rmdw <irq_00_handler, @CODE16>, <irq_01_handler, @CODE16>
  711.                 rmdw <irq_02_handler, @CODE16>, <irq_03_handler, @CODE16>
  712.                 rmdw <irq_04_handler, @CODE16>, <irq_05_handler, @CODE16>
  713.                 rmdw <irq_06_handler, @CODE16>, <irq_07_handler, @CODE16>
  714.  
  715. RESIDENTDATA end
  716.  
  717.  
  718. ;════════════════════════════════════════════════════════════════════════════;
  719.  
  720.  
  721. RESIDENTCODE begin
  722.  
  723. Align 16
  724. Proc    irq_00_handler                  ; Handler for IRQ 0 (timer).
  725.         or [cs:irq_flags],IRQ_00        ; Mark that IRQ 0 occurred.
  726.         jmp [dword cs:old_masterirqs]   ; Chain to old interrupt handler.
  727. Endp
  728.  
  729.  
  730. ;----------------------------------------------------------------------------;
  731.  
  732.  
  733. Proc    irq_01_handler                  ; Handler for IRQ 1 (keyboard).
  734.         or [cs:irq_flags],IRQ_01        ; Mark that IRQ 1 occurred.
  735.  
  736.         mov [cs:int_xxh_fcount],0          ; Zero int xxh force counter.
  737.         jmp [dword cs:old_masterirqs + 4]  ; Chain to old interrupt handler.
  738. Endp
  739.  
  740.  
  741. ;----------------------------------------------------------------------------;
  742.  
  743.  
  744. Proc    irq_02_handler                  ; Handler for IRQ 2 (slave PIC).
  745.         or [cs:irq_flags],IRQ_02        ; Mark that IRQ 2 occurred.
  746.  
  747.         mov [cs:int_xxh_fcount],0          ; Zero int xxh force counter.
  748.         jmp [dword cs:old_masterirqs + 8]  ; Chain to old interrupt handler.
  749. Endp
  750.  
  751.  
  752. ;----------------------------------------------------------------------------;
  753.  
  754.  
  755. Proc    irq_03_handler                  ; Handler for IRQ 3 (COM2).
  756.         or [cs:irq_flags],IRQ_03        ; Mark that IRQ 3 occurred.
  757.  
  758.         mov [cs:int_xxh_fcount],0          ; Zero int xxh force counter.
  759.         jmp [dword cs:old_masterirqs + 12] ; Chain to old interrupt handler.
  760. Endp
  761.  
  762.  
  763. ;----------------------------------------------------------------------------;
  764.  
  765.  
  766. Proc    irq_04_handler                  ; Handler for IRQ 4 (COM1).
  767.         or [cs:irq_flags],IRQ_04        ; Mark that IRQ 4 occurred.
  768.  
  769.         mov [cs:int_xxh_fcount],0          ; Zero int xxh force counter.
  770.         jmp [dword cs:old_masterirqs + 16] ; Chain to old interrupt handler.
  771. Endp
  772.  
  773.  
  774. ;----------------------------------------------------------------------------;
  775.  
  776.  
  777. Proc    irq_05_handler                  ; Handler for IRQ 5.
  778.         or [cs:irq_flags],IRQ_05        ; Mark that IRQ 5 occurred.
  779.  
  780.         mov [cs:int_xxh_fcount],0          ; Zero int xxh force counter.
  781.         jmp [dword cs:old_masterirqs + 20] ; Chain to old interrupt handler.
  782. Endp
  783.  
  784.  
  785. ;----------------------------------------------------------------------------;
  786.  
  787.  
  788. Proc    irq_06_handler                  ; Handler for IRQ 6.
  789.         or [cs:irq_flags],IRQ_06        ; Mark that IRQ 6 occurred.
  790.  
  791.         mov [cs:int_xxh_fcount],0          ; Zero int xxh force counter.
  792.         jmp [dword cs:old_masterirqs + 24] ; Chain to old interrupt handler.
  793. Endp
  794.  
  795.  
  796. ;----------------------------------------------------------------------------;
  797.  
  798.  
  799. Proc    irq_07_handler                  ; Handler for IRQ 7.
  800.         or [cs:irq_flags],IRQ_07        ; Mark that IRQ 7 occurred.
  801.  
  802.         mov [cs:int_xxh_fcount],0          ; Zero int xxh force counter.
  803.         jmp [dword cs:old_masterirqs + 28] ; Chain to old interrupt handler.
  804. Endp
  805.  
  806. RESIDENTCODE end
  807.  
  808.  
  809.  
  810. ;╔══════════════════════════════════════════════════════════════════════════╗;
  811. ;║ ▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓ INITIALIZATION PART OF PROGRAM ▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓ ║;
  812. ;╚══════════════════════════════════════════════════════════════════════════╝;
  813.  
  814. include "_tsrinit.ah"
  815. include "_cmdline.ah"
  816. include "_console.ah"
  817. include "_process.ah"
  818. include "_test.ah"
  819. include "_irq.ah"
  820. include "_vcpi.ah"
  821. include "_cpu.ah"
  822.  
  823.  
  824. ;════════════════════════════════════════════════════════════════════════════;
  825.  
  826.  
  827. KERNEL_NAME   equ "CPUidle for DOS"     ; Name of the kernel.
  828. KERNEL_FILE   equ "DOSidle"             ; Name of the .exe (compiled) kernel.
  829. KERNEL_ID     equ 0deedh                ; ID number of this program.
  830.  
  831. SYS_RAW         = 01h                   ;
  832. SYS_VCPI        = 02h                   ; Flags for PM hosts driving the
  833. SYS_DPMI        = 04h                   ; system.
  834.  
  835.  
  836. ;════════════════════════════════════════════════════════════════════════════;
  837.  
  838.  
  839. INITIALIZATIONSTACK begin
  840.         db 2000 dup (?)                 ; Stack for initialization part.
  841. INITIALIZATIONSTACK end
  842.  
  843.  
  844. ;════════════════════════════════════════════════════════════════════════════;
  845.  
  846.  
  847. INITIALIZATIONDATA begin
  848.  
  849. psp_seg         dw 0
  850. env_seg         dw 0
  851.  
  852. dos_version     dw 0                    ; MS-DOS version.
  853. apm_version     dw 0                    ; Advanced Power Management version.
  854. apm_state       db OFF                  ; State of APM (enabled, disabled).
  855.  
  856. sys_type        db SYS_RAW              ; Type of system (Raw, VCPI, DPMI).
  857.  
  858. ;- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ;
  859.  
  860. par_table       par_item <"-H", par_help>
  861.                 par_item <"-?", par_help>
  862.                 par_item <"-U", par_uninst>
  863.                 par_item <"-ON", par_on>
  864.                 par_item <"-OFF", par_off>
  865.                 par_item <"-CPU", par_cpu>
  866.                 par_item <"-HLT", par_hlt>
  867.                 par_item <"-APM", par_apm>
  868.                 par_item <"-FM0", par_noforce>
  869.                 par_item <"-FM1", par_weakforce>
  870.                 par_item <"-FM2", par_strongforce>
  871.         par_item <0>            ; Marks end of par_table.
  872.  
  873. ;- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ;
  874.  
  875. msg_intro       db KERNEL_NAME, " V2.10  [Build 0077]", NL
  876.                 db "Copyright (C) by Marton Balog, 1998.", NL,0
  877. msg_help        db "Syntax:    ", KERNEL_FILE, " [Options]", NL
  878.                 db "--------", NL,0
  879. msg_options_1   db "Standard   -On     Activate ", KERNEL_FILE, ".", NL
  880.                 db "Options:   -Off    Suspend ", KERNEL_FILE, ".", NL
  881.                 db "--------   -U      Uninstall ", KERNEL_FILE, ".", NL
  882.                 db "           -H, -?  Display this help message.", NL,0
  883. msg_options_2   db "Advanced   -Cpu    Optimize processor for performance.", NL
  884.                 db "Options:   -Hlt    Select cooling method: HLT idle cycles (default).", NL
  885.                 db "--------   -Apm    Select cooling method: APM V1.00+ cycles.", 0
  886. msg_options_3   db "           -Fm2    Select cooling strategy: Strong Forcing (default).", NL
  887.                 db "           -Fm1    Select cooling strategy: Weak Forcing.", NL
  888.                 db "           -Fm0    Select cooling strategy: No Forcing.", NL,0
  889. msg_examples_1  db "Example:   ", KERNEL_FILE, "             Install and activate ", KERNEL_FILE, ".", NL
  890.                 db "--------   ", KERNEL_FILE, " -Off        Suspend ", KERNEL_FILE, " temporarily.", 0
  891. msg_examples_2  db "           ", KERNEL_FILE, " -Fm2 -Apm   Enable Strong Forcing and use APM for cooling.",NL
  892.                 db "           ", KERNEL_FILE, " -Fm1 -Cpu   Enable Weak Forcing and optimize CPU.", NL,0
  893.  
  894. msg_inst        db NL, KERNEL_FILE, " installed successfully.",0
  895. msg_uninst      db KERNEL_FILE, " uninstalled successfully.",0
  896. msg_activate    db KERNEL_FILE, " is now activated.",0
  897. msg_suspend     db KERNEL_FILE, " is now suspended.",0
  898.  
  899. msg_marci       db "Zsuzsmi",0
  900. msg_nl          db NL, 0
  901. msg_na          db "N/A",0
  902.  
  903. msg_detect      db "DETECTING...", 0
  904. msg_cpudet      db "[Processor]:   ", 0
  905. msg_apmdet      db "[Power/Man]:   ", 0
  906. msg_osdet       db "[Op/System]:   ", 0
  907. msg_pmdet       db "[32-bit mode]: ", 0
  908.  
  909. msg_apm         db "APM V",0
  910. msg_apm_on      db " [Enabled].",0
  911. msg_apm_off     db " [Disabled].",0
  912. msg_msdos       db "MS-DOS V",0
  913. msg_msdos_std   db " [Standard].",0
  914. msg_msdos_win   db " [Windows 95/98].",0
  915. msg_raw         db "16-bit MS-DOS interface.",0
  916. msg_vcpi        db "32-bit VCPI interface.",0
  917. msg_dpmi        db "32-bit DPMI interface.",0
  918.  
  919. msg_optimize    db NL, "OPTIMIZING...", 0
  920. msg_cpuopt      db "[Processor]:   ", 0
  921. msg_optnomod    db "No modifications made",0 
  922.  
  923. err_str         db "FATAL ",0
  924. err_resize      db "[#10]: Failed to resize program memory.",0
  925. err_notinst     db "[#20]: ", KERNEL_FILE, " is not installed.",0
  926. err_inst        db "[#21]: ", KERNEL_FILE, " is already installed.",0
  927. err_uninst      db "[#22]: Cannot uninstall ", KERNEL_FILE ,".",0
  928. err_activate    db "[#23]: ", KERNEL_FILE, " is already activated.",0
  929. err_suspend     db "[#24]: ", KERNEL_FILE, " is already suspended.",0
  930. err_cpu         db "[#30]: A 386 CPU or better is required.",0
  931. err_dos_vers    db "[#32]: MS-DOS 5.00 or later is required.",0
  932. err_cmdln       db "[#40]: Invalid command-line switch.",0
  933. err_v86         db "[#50]: CPU in V86 mode and no VCPI or DPMI host present.",0
  934.  
  935. INITIALIZATIONDATA end
  936.  
  937.  
  938. ;════════════════════════════════════════════════════════════════════════════;
  939.  
  940.  
  941. INITIALIZATIONCODE begin
  942.  
  943. Proc    error_exit                      ; Exits with error message.
  944.     push si
  945.     lea si,[err_str]                ;
  946.     call con_writef                 ; Print "[FATAL]: "
  947.     pop si
  948.  
  949.     sti
  950.     call con_writeln                ; Print error message.
  951.     exit 0                          ; Off we go...
  952.     ret
  953. Endp
  954.  
  955.  
  956. ;----------------------------------------------------------------------------;
  957.  
  958.  
  959. Proc    init
  960.     mov ax,cs                       ;
  961.     mov ds,ax                       ; Set data segment.
  962.  
  963.     mov [psp_seg],es                ; Save PSP segment.
  964.     mov ax,[es:2ch]                 ;
  965.     mov [env_seg],ax                ; Save enviroment segment.
  966.  
  967.     lea si,[msg_intro]              ;
  968.     call con_writeln                ; Display program name, copyright...
  969.  
  970.     call test_cpu                   ; Get CPU family number.
  971.     lea si,[err_cpu]                ;
  972.     cmp al,3                        ; Less than a 386 (286-)?
  973.     jb error_exit                   ; Yep, error.
  974.  
  975.         mov ax,3000h                    ;
  976.     int 21h                         ; Get DOS version.
  977.         mov [dos_version],ax            ; Save it.
  978.  
  979.     lea si,[err_dos_vers]           ; Prepare for error.
  980.     cmp al,5                        ; Is DOS new enough (5.00+)?
  981.         jb error_exit                   ; No (4.99-) fail.
  982.  
  983.         mov ax,[psp_seg]                ; Shrink DOSidle's memory block to
  984.         mov cx,1000h                    ; 64 KBs now, TSR will shrink more
  985.         call mem_lresize                ; later...
  986.     ret
  987. Endp
  988.  
  989.  
  990. ;----------------------------------------------------------------------------;
  991.  
  992.  
  993. Proc    par_help
  994.     lea si,[msg_help]               ;
  995.     call con_writeln                ; Display help message.
  996.  
  997.         lea si,[msg_options_1]          ;
  998.         call con_writeln                ; Display options help part 1.
  999.  
  1000.         lea si,[msg_options_2]          ;
  1001.         call con_writeln                ; Display options help part 2.
  1002.  
  1003.         lea si,[msg_options_3]          ;
  1004.         call con_writeln                ; Display options help part 3.
  1005.  
  1006.         lea si,[msg_examples_1]         ;
  1007.         call con_writeln                ; Display examples help part 1.
  1008.  
  1009.         lea si,[msg_examples_2]         ;
  1010.         call con_writeln                ; Display examples help part 2.
  1011.     exit 0
  1012. Endp
  1013.  
  1014. ;- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ;
  1015.  
  1016. Proc    par_uninst
  1017.     mov dx,KERNEL_ID                ;
  1018.     call tsr_instcheck              ; Is kernel installed already?
  1019.  
  1020.     lea si,[err_notinst]            ;
  1021.     test ax,ax                      ; AX == 0 if not installed.
  1022.     je error_exit                   ; Nope, can't uninstall, error.
  1023.  
  1024.     mov dx,KERNEL_ID                ;
  1025.         call tsr_uninstall              ; Try to uninstall kernel.
  1026.  
  1027.         lea si,[err_uninst]             ; Prepare for error.
  1028.         test ax,ax                      ; Uninstallation failed?
  1029.         jz error_exit                   ; Yes, fail.
  1030.  
  1031.         lea si,[msg_uninst]             ;
  1032.     call con_writeln                ; Print success message.
  1033.     exit 0                          ; Quit.
  1034. Endp
  1035.  
  1036. ;- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ;
  1037.  
  1038. Proc    par_on
  1039.     mov dx,KERNEL_ID                ;
  1040.     call tsr_instcheck              ; Is kernel installed already?
  1041.  
  1042.     test ax,ax                      ; AX == 0 if not installed.
  1043.         jnz short @@on                  ; It's installed, try to activate.
  1044.  
  1045.         ret                             ; Do normal install if it's 1st time.
  1046.  
  1047. @@on:   mov dx,KERNEL_ID                ;
  1048.         call tsr_reactivate             ; Try to reactivate int handlers.
  1049.  
  1050.         lea si,[err_activate]           ;
  1051.         test ax,ax                      ; Reactivation of ints failed?
  1052.         jz error_exit                   ; Yes, fail.
  1053.  
  1054.         lea si,[msg_activate]           ;
  1055.         call con_writeln                ; Print success message.
  1056.         exit 0                          ; Quit.
  1057. Endp
  1058.  
  1059. ;- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ;
  1060.  
  1061. Proc    par_off
  1062.     mov dx,KERNEL_ID                ;
  1063.     call tsr_instcheck              ; Is kernel installed already?
  1064.  
  1065.     lea si,[err_notinst]            ;
  1066.     test ax,ax                      ; AX == 0 if not installed.
  1067.         jz error_exit                   ; Nope, can't suspend, error.
  1068.  
  1069.         mov dx,KERNEL_ID                ;
  1070.         call tsr_suspend                ; Try to suspend interrupt handlers.
  1071.  
  1072.         lea si,[err_suspend]            ;
  1073.         test ax,ax                      ; Suspension of ints failed?
  1074.         jz error_exit                   ; Yes, fail.
  1075.         
  1076.         lea si,[msg_suspend]            ;
  1077.         call con_writeln                ; Print success message.
  1078.         exit 0                          ; Quit.
  1079. Endp
  1080.  
  1081. ;- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ;
  1082.  
  1083. Proc    par_cpu
  1084.         or [mode_flags],MODE_OPTIMIZE   ; Request CPU optimization.
  1085.         ret
  1086. Endp
  1087.  
  1088. ;- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ;
  1089.  
  1090. Proc    par_apm
  1091.         or [mode_flags],MODE_APM        ;
  1092.         and [mode_flags],not MODE_HLT   ; Set APM MODE in config flags.
  1093.         ret
  1094. Endp
  1095.  
  1096. ;- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ;
  1097.  
  1098. Proc    par_hlt
  1099.         or [mode_flags],MODE_HLT        ; 
  1100.         and [mode_flags],not MODE_APM   ; Set HLT MODE in config flags.
  1101.         ret
  1102. Endp
  1103.  
  1104. ;- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ;
  1105.  
  1106. Proc    par_noforce
  1107.         or [mode_flags],MODE_NOFORCE    ; Set NO FORCE in config flags.
  1108.  
  1109.         and [mode_flags],not MODE_WFORCE
  1110.         and [mode_flags],not MODE_SFORCE
  1111.         ret
  1112. Endp
  1113.  
  1114. ;- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ;
  1115.  
  1116. Proc    par_weakforce
  1117.         or [mode_flags],MODE_WFORCE     ; Set WEAK FORCE in config flags.
  1118.  
  1119.         and [mode_flags],not MODE_SFORCE
  1120.         and [mode_flags],not MODE_NOFORCE
  1121.         ret
  1122. Endp
  1123.  
  1124. ;- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ;
  1125.  
  1126. Proc    par_strongforce
  1127.         or [mode_flags],MODE_SFORCE     ; Set STRONG FORCE in config flags.
  1128.  
  1129.         and [mode_flags],not MODE_WFORCE
  1130.         and [mode_flags],not MODE_NOFORCE
  1131.         ret
  1132. Endp
  1133.  
  1134. ;- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ;
  1135.  
  1136. Proc    read_cmdln
  1137.     mov di,80h                      ;
  1138.     mov es,[psp_seg]                ; ES:DI = ptr to command-line.
  1139.     lea si,[par_table]              ; DS:SI = ptr to parameter_table.
  1140.  
  1141.     call parse_cmdln                ; Process the command line.
  1142.     lea si,[err_cmdln]              ;
  1143.     jc error_exit                   ; Quit if invalid command-line switch.
  1144.     ret
  1145. Endp
  1146.  
  1147.  
  1148. ;----------------------------------------------------------------------------;
  1149.  
  1150.  
  1151. Proc    init_modes
  1152.         test [mode_flags],MODE_NOFORCE  ; FORCE MODE disabled?
  1153.         jz short @@sfor                 ; No.
  1154.  
  1155.         mov [byte int_xxh_forcehlt],0c3h  ; Disable FORCE HLT/APM procedure.
  1156.  
  1157. @@sfor: test [mode_flags],MODE_SFORCE   ; STRONG FORCE MODE enabled?
  1158.         jz short @@apm                  ; No.
  1159.  
  1160.         cmp [sys_type],SYS_DPMI         ; Running under DPMI (possibly Win95)?
  1161.         jne short @@apm                 ; No
  1162.  
  1163.         cmp [byte dos_version],7        ; Windows MS-DOS 7.00+ (Win95)?
  1164.         jb short @@apm                  ; No.
  1165.  
  1166.         or [mode_flags],MODE_WFORCE     ; Set WEAK FORCE in config flags.
  1167.         and [mode_flags],not MODE_SFORCE
  1168.         and [mode_flags],not MODE_NOFORCE
  1169.  
  1170. @@apm:  test [mode_flags],MODE_APM      ; APM usage requested?
  1171.         jz short @@cpu                  ; No.
  1172.  
  1173.         and [mode_flags],not MODE_APM   ; Assume APM is disabled/disengaged.
  1174.  
  1175.         cmp [apm_state],OFF             ; APM disabled/disengaged?
  1176.         je short @@cpu                  ; Yes, no APM.
  1177.  
  1178.         mov ax,5304h                    ;
  1179.         xor bx,bx                       ;
  1180.         int 15h                         ; Disconnect Real-mode APM interface.
  1181.         jc short @@cpu                  ; Call failed, no APM.
  1182.  
  1183.         mov ax,5301h                    ;
  1184.         xor bx,bx                       ;
  1185.         int 15h                         ; Connect Real-mode APM interface.
  1186.         jc short @@cpu                  ; Call failed, no APM.
  1187.  
  1188.         mov ax,530eh                    ;
  1189.         xor bx,bx                       ;
  1190.         mov cx,[apm_version]            ;
  1191.         xchg cl,ch                      ; Connect appropriate version of APM
  1192.         int 15h                         ; BIOS (needed for V1.00+).
  1193.         jc short @@cpu                  ; Call failed, no APM.
  1194.  
  1195.         mov ax,5305h                    ;
  1196.         int 15h                         ; Call APM FN to put the CPU idle.
  1197.         jc short @@cpu                  ; Call failed, no APM.
  1198.         
  1199.         or [mode_flags],MODE_APM        ; It's safe to use APM...
  1200.  
  1201. @@cpu:  test [mode_flags],MODE_OPTIMIZE ; CPU optimization requested?
  1202.         jz short @@done                 ; No.
  1203.  
  1204.         lea si,[msg_optimize]           ;
  1205.         call con_writeln                ; Print optimization message.
  1206.  
  1207.         lea si,[msg_cpudet]             ;
  1208.         call con_writef                 ; Print message for CPU detection.
  1209.  
  1210.         call cpu_optimize               ; Optimize CPU.
  1211.         lea si,[msg_optnomod]           ; Assume optimization failed.
  1212.         jc short @@prnt                 ; Go..
  1213.  
  1214.         call cpu_getname                ;
  1215.         lea si,[cpu_name]               ; Get full name of CPU.
  1216.  
  1217. @@prnt: call con_writef                 ; Print results of optimization.
  1218.  
  1219.         mov al,'.'                      ;
  1220.         call con_writech                ; Period.
  1221.  
  1222.         mov al,CR                       ;
  1223.         call con_writech                ;
  1224.         mov al,LF                       ;
  1225.         call con_writech                ; New line.
  1226.  
  1227. @@done: ret
  1228. Endp
  1229.  
  1230.  
  1231. ;----------------------------------------------------------------------------;
  1232.  
  1233.  
  1234. Proc    check_system
  1235.     call test_vcpi                  ; Running under VCPI server?
  1236.     jne short @@dpmi                ; No.
  1237.  
  1238.         mov [sys_type],SYS_VCPI         ; Mark that running under VCPI.
  1239.         jmp short @@done
  1240.  
  1241. @@dpmi: call test_dpmi                  ; Running under DPMI host?
  1242.     jne short @@v86                 ; No.
  1243.  
  1244.         mov [sys_type],SYS_DPMI         ; Mark that running under DPMI.
  1245.         jmp short @@done
  1246.  
  1247. @@v86:  call test_v86                   ; Running in V86 mode without PM host?
  1248.     lea si,[err_v86]                ; Yes, can't execute HLT instruction,
  1249.     je error_exit                   ; fail program.
  1250. @@done: ret
  1251. Endp
  1252.  
  1253.  
  1254. ;----------------------------------------------------------------------------;
  1255.  
  1256.  
  1257. Proc    hook_ints
  1258.     xor ax,ax            ;
  1259.     mov gs,ax            ; GS = segment of IVT.
  1260.  
  1261.         ;-  -  -  -  -  -  -  -  -  -  -;
  1262.         mov eax,[gs:(10h * 4)]          ;
  1263.         mov [dword old_int_10h],eax     ; Get and save original int 10h.
  1264.  
  1265.         mov eax,[gs:(15h * 4)]          ;
  1266.         mov [dword old_int_15h],eax     ; Get and save original int 15h.
  1267.  
  1268.         mov eax,[gs:(14h * 4)]          ;
  1269.         mov [dword old_int_14h],eax     ; Get and save original int 14h.
  1270.  
  1271.         mov eax,[gs:(16h * 4)]          ;
  1272.     mov [dword old_int_16h],eax     ; Get and save original int 16h.
  1273.  
  1274.     mov eax,[gs:(21h * 4)]          ;
  1275.     mov [dword old_int_21h],eax     ; Get and save original int 21h.
  1276.  
  1277.         mov eax,[gs:(2fh * 4)]          ;
  1278.         mov [dword old_int_2fh],eax     ; Get and save original int 2fh.
  1279.         ;-  -  -  -  -  -  -  -  -  -  -;
  1280.  
  1281.         ;-  -  -  -  -  -  -  -  -  -  -;
  1282.         mov ax,@CODE16                  ;
  1283.         shl eax,16                      ; High WORD of EAX = CODE16.
  1284.  
  1285.         mov bl,10h                      ; BL = int number of video handler.
  1286.         mov ax,offset int_10h_handler   ; EAX = new handler for int 10h.
  1287.         call tsr_hookint                ; Hook int 10h.
  1288.  
  1289.         mov bl,15h                      ; BL = int number of AT services.
  1290.         mov ax,offset int_15h_handler   ; EAX = new handler for int 15h.
  1291.         call tsr_hookint                ; Hook int 15h.
  1292.  
  1293.         mov bl,14h                      ; BL = int number of BIOS COM handler.
  1294.         mov ax,offset int_14h_handler   ; EAX = new handler for int 14h.
  1295.         call tsr_hookint                ; Hook int 14h.
  1296.  
  1297.         mov bl,16h                      ; BL = int number of keyboard handler.
  1298.         mov ax,offset int_16h_handler   ; EAX = new handler for int 16h.
  1299.         call tsr_hookint                ; Hook int 16h.
  1300.  
  1301.         mov bl,21h                      ; BL = int number of DOS FNs handler.
  1302.         mov ax,offset int_21h_handler   ; EAX = new handler for int 21h.
  1303.         call tsr_hookint                ; Hook int 21h.
  1304.  
  1305.         mov bl,2fh                      ; BL = int # of DOS Multiplex handler.
  1306.         mov ax,offset int_2fh_handler   ; EAX = new handler for int 2fh.
  1307.         call tsr_hookint                ; Hook int 2fh.
  1308.         ;-  -  -  -  -  -  -  -  -  -  -;
  1309.         ret
  1310. Endp
  1311.  
  1312.  
  1313. ;----------------------------------------------------------------------------;
  1314.  
  1315.  
  1316. Proc    hook_irqs
  1317.     xor ax,ax            ;
  1318.     mov gs,ax            ; GS = segment of IVT.
  1319.  
  1320.         ;-  -  -  -  -  -  -  -  -  -  -;
  1321. @@vcpi: cmp [sys_type],SYS_VCPI         ; Running under VCPI?
  1322.         jne short @@dpmi                ; No.
  1323.  
  1324.         call vcpi_getpic                ; Get VCPI IRQ mappings.
  1325.         jmp short @@hook
  1326.  
  1327. @@dpmi: cmp [sys_type],SYS_DPMI         ; Running under DPMI?
  1328.         jne short @@raw                 ; No.
  1329.  
  1330.         call irq_getpic                 ; Assume RM IRQ settings (should work).
  1331.         jmp short @@hook
  1332.  
  1333. @@raw:  call irq_getpic                 ; Get IRQ mappings.
  1334.         ;-  -  -  -  -  -  -  -  -  -  -;
  1335.  
  1336.         ;-  -  -  -  -  -  -  -  -  -  -;
  1337. @@hook: movzx ebx,bl                    ; EBX = base int # for master PIC.
  1338.         mov cx,8                        ; CX = number of IRQ in master PIC.
  1339.         xor di,di                       ; DI = index to irq arrays.
  1340.  
  1341. @@mstr: mov eax,[gs:(ebx * 4)]               ;
  1342.         mov [dword old_masterirqs + di],eax  ; Get and save old IRQ handler.
  1343.  
  1344.         mov eax,[dword new_masterirqs + di]  ; Get new handler of IRQ.
  1345.         call tsr_hookint                ; Hook IRQ.
  1346.         inc bl                          ; BL = next interrupt # for IRQ.
  1347.         add di,4                        ; DI = next IRQ number.
  1348.         loop @@mstr
  1349.         ;-  -  -  -  -  -  -  -  -  -  -;
  1350. @@done: ret
  1351. Endp
  1352.  
  1353.  
  1354. ;----------------------------------------------------------------------------;
  1355.  
  1356.  
  1357. Proc    detect_cpu
  1358.         lea si,[msg_cpudet]             ;
  1359.         call con_writef                 ; Print message for CPU detection.
  1360.  
  1361.         call cpu_getname                ; Get full name of CPU.
  1362.         lea si,[cpu_name]               ;
  1363.         call con_writef                 ; Print it.
  1364.  
  1365.         mov al,'.'                      ;
  1366.         call con_writech                ; Period.
  1367.  
  1368.         lea si,[msg_nl]                 ;
  1369.         call con_writef                 ; New Line.
  1370.         ret
  1371. Endp
  1372.  
  1373. ;- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ;
  1374.  
  1375. Proc    detect_os
  1376.         lea si,[msg_osdet]              ;
  1377.         call con_writef                 ; Print message for OS detection.
  1378.  
  1379.         lea si,[msg_msdos]              ;
  1380.         call con_writef                 ; Print "MS-DOS V"
  1381.  
  1382.         movzx eax,[byte dos_version]    ;
  1383.         call con_writedec               ; Print major version number.
  1384.  
  1385.         mov al,'.'                      ;
  1386.         call con_writech                ; Put a decimal point for version.
  1387.  
  1388.         movzx eax,[byte dos_version+1]  ;
  1389.         call con_writedec               ; Print minor version number.
  1390.  
  1391.         lea si,[msg_msdos_std]          ; Assume MS-DOS V6.22-
  1392.         cmp [byte dos_version],7        ; Is it V7.00+ (for Win95/98)?
  1393.         jb short @@osok                 ; No.
  1394.  
  1395.         lea si,[msg_msdos_win]          ; It's V7.00+ (for Win95/98).
  1396.  
  1397. @@osok: call con_writeln                ; Print DOS type.
  1398.         ret
  1399. Endp
  1400.  
  1401. ;- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ;
  1402.  
  1403. Proc    detect_apm
  1404.         lea si,[msg_apmdet]             ;
  1405.         call con_writef                 ; Print message for APM detection.
  1406.  
  1407.         stc                             ;
  1408.         mov ax,5300h                    ;
  1409.         mov bx,0                        ;
  1410.         int 15h                         ; APM V1.00+: installation check.
  1411.         jnc short @@cont                ; Yes, it's installed, continue.
  1412.         
  1413.         lea si,[msg_na]                 ;
  1414.         call con_writeln                ; No APM, print N/A message.
  1415.         jmp short @@done                ; Finish.
  1416.  
  1417. @@cont: xchg al,ah                      ; AL = major version, AH = minor.
  1418.         mov [apm_version],ax            ; Save APM version.
  1419.  
  1420.         lea si,[msg_apm]                ;
  1421.         call con_writef                 ; Print "APM V"
  1422.  
  1423.         movzx eax,[byte apm_version]    ;
  1424.         call con_writedec               ; Print major version number.
  1425.  
  1426.         mov al,'.'                      ;
  1427.         call con_writech                ; Put a decimal point for version.
  1428.  
  1429.         movzx eax,[byte apm_version+1]  ;
  1430.         call con_writedec               ; Print minor version number.
  1431.  
  1432.         test cx,18h                     ; Is the APM disabled/disengaged?
  1433.         jnz short @@off                 ; Yes.
  1434.  
  1435. @@on:   mov [apm_state],ON              ; Mark that APM is unusable.
  1436.         lea si,[msg_apm_on]             ; It's enabled.
  1437.         jmp short @@done                ; Finish up.
  1438.  
  1439. @@off:  mov [apm_state],OFF             ; Mark that APM is unusable.
  1440.         lea si,[msg_apm_off]            ; It's disabled.
  1441.  
  1442. @@done: call con_writeln                ; Print APM state.
  1443.         ret
  1444. Endp
  1445.  
  1446. ;- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ;
  1447.  
  1448. Proc    detect_pm
  1449.         lea si,[msg_pmdet]              ;
  1450.         call con_writef                 ; Print message for PM detection.
  1451.  
  1452.         lea si,[msg_raw]                ; Assume raw DOS.
  1453.         test [sys_type],SYS_RAW         ; Running under raw DOS?
  1454.         jnz short @@pmok                ; Yes, done.
  1455.  
  1456.         lea si,[msg_vcpi]               ; Assume VCPI.
  1457.         test [sys_type],SYS_VCPI        ; Running under VCPI?
  1458.         jnz short @@pmok                ; Yes, done.
  1459.  
  1460.         lea si,[msg_dpmi]               ; Now it's DPMI for sure.
  1461. @@pmok: call con_writeln                ; Print PM system.
  1462.         ret
  1463. Endp
  1464.  
  1465. ;- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ;
  1466.  
  1467. Proc    info_detect
  1468.         lea si,[msg_detect]             ;
  1469.         call con_writeln                ; Print detection message.
  1470.  
  1471.         call detect_cpu                 ; Print CPU detection results.
  1472.         call detect_apm                 ; Print APM detection results.
  1473.         call detect_os                  ; Print OS detection results.
  1474.         call detect_pm                  ; Print PM host detection results.
  1475.         ret
  1476. Endp
  1477.  
  1478.  
  1479. ;----------------------------------------------------------------------------;
  1480.  
  1481.  
  1482. Proc    install_kernel
  1483.     lea si,[msg_inst]               ;
  1484.     call con_writeln                ; Print success message.
  1485.  
  1486.         mov cx,RESIDENT_END             ;
  1487.     mov dx,KERNEL_ID                ;
  1488.     mov bx,[psp_seg]                ;
  1489.     mov ax,[env_seg]                ;
  1490.     call tsr_install                ; Make kernel TSR.
  1491. Endp
  1492.  
  1493.  
  1494. ;----------------------------------------------------------------------------;
  1495.  
  1496.  
  1497. Proc    main
  1498.     call init                       ; Do general startup work.
  1499.     call read_cmdln                 ; Read cmd-ln params (maybe uninstall).
  1500.  
  1501.     mov dx,KERNEL_ID                ;
  1502.     call tsr_instcheck              ; Is kernel installed already?
  1503.  
  1504.     lea si,[err_inst]               ;
  1505.     cmp ax,1                        ; AX == 1 if installed.
  1506.     je error_exit                   ; Yes, quit now (don't install twice).
  1507.  
  1508.         call check_system               ; Check for VCPI, DPMI, etc.
  1509.         call info_detect                ; Detect CPU, system, APM, etc.
  1510.         call init_modes                 ; Init FORCE, Test and other modes.
  1511.         
  1512.         call hook_ints                  ; Hook needed interrupts.
  1513.         call hook_irqs                  ; Hook needed IRQs.
  1514.  
  1515.         call cpu_powersave              ; Enable power saving features.
  1516.         call install_kernel             ; Make kernel TSR.
  1517. Endp
  1518.  
  1519. INITIALIZATIONCODE end
  1520. End     main
  1521.  
  1522.