;COMMENT |
;== License =================================================================
;
;  Copyright (c) 1995, 1996, 2004, Robert Rothenburg Walking-Owl.
;  (Portions by Colin Plumb.)  All rights reserved.
;
;  Redistribution and use in source and binary forms, with or without
;  modification, are permitted provided that the following conditions
;  are met:
;
;    * Redistributions of source code must retain the above copyright
;      notice, this list of conditions and the following disclaimer.
;
;    * Redistributions in binary form must reproduce the above copyright
;      notice, this list of conditions and the following disclaimer in
;      the documentation and/or other materials provided with the
;      distribution.
;
;    * Neither the names of the authors nor the names of its
;      contributors may be used to endorse or promote products derived
;      from this software without specific prior written permission.
;
;  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
;  "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
;  LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
;  FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
;  COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
;  INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
;  BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
;  LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
;  CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
;  LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
;  ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
;  POSSIBILITY OF SUCH DAMAGE.
;
;===========================================================================|

; --------------------------------------------------------------------------
; NOISE.SYS v0.53+ API Routines and Data

; --------------------------------------------------------------------------
IOCTL_Read:                    ; Updated IOCTL
                mov     si, ControlOut
                mov     cx, [es:di+ReqHdr.Siz]  ; Bytes to read
                cmp     cx, szControlOut
                jna     SHORT @@IOCTL_Read_irSizeOk
                mov     cx, szControlOut        ; Don't read more than that!
@@IOCTL_Read_irSizeOk:
                mov     [es:di+ReqHdr.Siz], cx
                les     di, [es:di+ReqHdr.Addr] ; Address to read to
                cld
                rep     movsb
                jmp     rdevok


; --------------------------------------------------------------------------
%DEFINE	IdTag	"noiz"  ; Id = 0x6e6f697a

ControlOut:
                DW      szControlOut    ; Size of the output record
ReturnTag       DD      IdTag           ; Id tag
                DW      NoiseVersion    ; Version
HookAPI         DB      DefaultInt      ; Int used by API
HookFunc        DB      'n'             ; AH = HookFunc
FarCallAddr     DW      FarCallHook
                DW      0
Flags:            ; Flags
                DD      DEFAULTFLAGS   
Quality         DW     QualityThreshold ; Output threshold
UsageFlag       DB      0               ; Multi-tasking friendliness
DosVersionMaj   DB      0               ; DOS Version (Major)
@StartTables:            ; -----
Counter         DD      0               ; Counter used for estimating entropy
FreshCount      DW      0               ; total fresh bits in pool
OutQueue        DW      0               ; Bytes waiting in outpool[]
szControlOut    equ     $-ControlOut

LastTick:     ; Last sample added to entropy pool
                DW      0
  %if N
CurrentHash:  ; hash of last N samples (for table lookup)
                DW      0
lastNtable:   ; The last N samples hashed with index
                times	N	DW      0
indexNtable:
                DW      (N-1)*2
  %endif
deltatable:   ; Table of when a hash last occurred
                times	TABLESIZE	DW      0
szTables        equ     $-@StartTables

; --------------------------------------------------------------------------
@ReturnJump:
                resd	1
ResetNoiseHook:
; ResetNoiseHook() -  resets tables, etc. Trashes ax, cx, di, es, flags
; Returns: NC if Ok, CF if driver is currently in use.
  %if 0 ; (!) Buggy: often the driver is in use, and can't be reset
                cmp     BYTE [UsageFlag], 0
                je      @Resettable
                stc
                retf
@Resettable:
                cld
                xor     ax, ax
                push    cs
                pop     es
                mov     di, @StartTables
                mov     cx, szTables/2
                rep     stosw
                mov     WORD [Partial], 8000h
                clc
  %endif
                retf
                ibm_isp NoiseHook, ResetNoiseHook
@NoiseHookEntry:
                cmp     ah, [cs:HookFunc]  ; are we being called?
                je      SHORT @HelloSailor ; if yes, groovy
                jmp     FAR [cs:NoiseHook+2] ; otherwise continue
FarCallHook:                ; hook for far calls
                pushf
                jmp     SHORT @HelloSailor ; ignore AH (v0.6)
@ReturnOk:      dec     BYTE [UsageFlag]
                clc                        ; CF=0 (Ok)
@ReturnMisc:    pop     bp
                pop     si
                pop     ds
                jmp     FAR [cs:@ReturnJump]
@AlreadyUsed:   mov     al, apiUseErr      ; API already in use
@ReturnErr:     dec     BYTE [UsageFlag]
                stc                        ; CF=1 (Error)
                jmp     SHORT @ReturnMisc
;;                pop     bp
;;                pop     si
;;                pop     ds
;;                jmp     DWORD PTR cs:[@ReturnJump]
@HelloSailor:   pop     DWORD [cs:@ReturnJump]
                popf
                push	ds
                push	si
                push	bp
                push	cs
                pop     ds
                inc     BYTE [UsageFlag]
                cmp     al, NumFunctions
                jb      SHORT @FuncOk
@Invalid:       mov     al, apiInvalid     ; Bad function number
                jmp     SHORT @ReturnErr
@FuncOk:        mov     ah, 0
                add     ax, ax
                mov     si, ax
                jmp     WORD [@FuncTbl+si]
@FuncTbl:
                DW      @AMIS00       ; Installation Check (AL=0)
                DW      @AMIS01       ; Get Entryy Point (AL=1)
                DW      @AMISUnimplem ;
                DW      @AMISUnimplem ;
                DW      @AMIS04       ; Get Interrupt Hook List (AL=4)
                DW      @AMISUnimplem ;
                DW      @AMIS06       ; Reserved for future use
                DW      @Invalid      ;
                DW      @Invalid      ;
                DW      @Invalid      ;
                DW      @Invalid      ;
                DW      @Invalid      ;
                DW      @Invalid      ;
                DW      @Invalid      ;
                DW      @Invalid      ;
                DW      @Invalid      ;
                DW      @InstallCheck ; AL = 10h
                DW      @GetEstimate  ; AL = 11h
                DW      @SampleTimer, @AddSample
                DW      @GetFlags, @SetFlags
                DW      @ReadPRNG, @ReadRAND, @ReadControlTbl
NumFunctions	equ ($ - @FuncTbl)/2

@AMIS00:            ; Installation Check (AL=0)
                mov     al, apiOk
                mov     cx, NoiseVersion
                mov     dx, cs
                mov     di, SignatureString
                jmp     SHORT @ReturnOk
SignatureString:
                DB      "WlkngOwl", "NoiseSYS", 0
@AMIS01:            ; Get Entry Point (AL=1)
                mov     al, apiOk
                mov     dx, cs
                mov     bx, FarCallHook ; or should this be DI reg?
                jmp     @ReturnOk
@HookList:
        %REP 12 ; (!) Install_Int() routine does not check boundaries here!
                DB      DefaultInt
                DW      NoiseHook
        %ENDREP
@AMIS04:
                mov     al, 04h
                mov     dx, cs
                mov     bx, @HookList
                jmp     @ReturnOk
@AMIS06:    ; AMIS v3.5.9 proposed spec
                mov     dx, cs
                mov     bx, rheader
                mov     ax, 2
                jmp     @ReturnOk
@AMISUnimplem:
                mov     al, apiInvalid
                jmp     @ReturnErr
; --------------------------------------------------------------------------
@InstallCheck:            ; Get Driver Status (AL=10h)
                mov     bh, [UsageFlag] ;          BH  = Usage Count
                mov     bl, (NumFunctions-1) ;     BL  = Highest function
  %ifndef POOLSIZE
                mov     dx, 64          ;          DX  = Max bytes waiting
  %else
                mov     dx, POOLSIZE*4
  %endif
@GetWaiting:            ;          CX  = No. bytes waiting
  %ifndef POOLSIZE
                mov     cx, [FreshCount]
                shr     cx, 3+FRACBITS
  %else
                mov     cx, [OutQueue]
  %endif
                mov     ax, (__CPU << 8)+apiOk ;  AH  = Build CPU, AL = Ok
                jmp     @ReturnOk
@GetEstimate:            ; Get Estimated Entropy  (AH=11h)
                movzx   ebx, WORD [OutQueue]
                shl     ebx, 3+FRACBITS
                mov     al, apiOk
  %ifn __FULLHASH
                movzx   edx, WORD [FreshCount]
                add     ebx, edx        ;          EBX = Estimated bit count
  %endif
                mov     cl, FRACBITS    ;          CL  = FRACBITS
                mov     edx, [Counter]  ;          EDX = No. of samples
                jmp     @ReturnOk
  %if __AllowAddAPI
@SampleTimer:            ; Sample timer (AL=12h)
                call    Sample
                jmp     SHORT @GetWaiting
@AddSample:            ; Add sample (AL=13h, DX=sample)
                mov     ax, dx
                call    TrackDeltas
                jmp     SHORT @GetWaiting
  %else
@SampleTimer:            ; Sample timer (AL=12h)
@AddSample:            ; Add sample (AL=13h)
  %endif
@Disabled:
                mov     al, apiDisabled
                jmp     @ReturnErr
@GetFlags:            ; Get flags (AL=14h)
                mov     al, apiOk
                mov     bx, [Flags]     ; BX = flags
                mov     cx, SettableFlagsMask
                jmp     @ReturnOk
@SetFlags:            ; Set flags (AL=15h)
                and     bx, SettableFlagsMask
                and     WORD [Flags], ~ SettableFlagsMask
                or      [Flags], bx
                jmp     SHORT @GetFlags
@ReadPRNG:            ; Read URANDOM bytes (AL=16h)
                push    cx
                cld
                mov     bx, [BytesAvail] ; CX=Length, ES:[DI]->buffer
                call    Read
                mov     al, apiOk
                pop     cx
                jmp     @ReturnOk
@ReadRAND:            ; Read RANDOM bytes
                mov     al, apiUseErr
                cmp     BYTE [UsageFlag], 1
                ja      SHORT @rrReadNothing
  %ifdef POOLSIZE                       ; Read bytes from output pool
                mov     ax, [OutQueue]  ; check if pool has any bytes
                test    ax, ax
                jnz     SHORT @rrAboveThresh0
                mov     al, apiEmpty
@rrReadNothing:
                xor     cx, cx
                jmp     @ReturnErr
@rrAboveThresh0:
  %else                                  ; Read bytes from hash
                mov     ax, [FreshCount] ; check if pool has entropy
                cmp     ax, EntropyThreshold ; (*) Change to mem ref?
                ja      SHORT @rrAboveThresh1
                mov     al, apiUseErr
@rrReadNothing:
                xor     cx, cx
                jmp     @ReturnErr
@rrAboveThresh1:
                shr     ax, 3+FRACBITS         ; bytes requested > entropy?
  %endif
                cmp     cx, ax
                jna     SHORT @rrEnough
                mov     cx, ax
@rrEnough:
  %ifdef POOLSIZE
                sub     [OutQueue], cx
                mov     bx, [OutIndex]
                add     bx, 3
                and     bx, (POOLSIZE*4)-1
                push    cx
                cld
@rrPoolCopyLoop:
                mov     al, bl
                xchg    al, BYTE [OutPool+bx]
                dec     bx
@rrr00:         and     bx, (POOLSIZE*4)-1
                stosb
                loop    @rrPoolCopyLoop
                pop     cx
                mov     [OutIndex], bx
  %else
                jmp     SHORT @ReadPRNG
  %endif
@rrExit:        mov     al, apiOk
                jmp     @ReturnOk
@ReadControlTbl:
  %if 1
                jmp     @Disabled
  %else
                mov     si, ControlOut
                cmp     cx, szControlOut
                jna     SHORT @@ItsTime_rctSizeOk
                mov     cx, szControlOut        ; Don't read more than that!
@@ItsTime_rctSizeOk:
                mov     ax, cx
                cld
                rep     movsb
                mov     cx, ax
                jmp     SHORT @rrExit
   %endif

; --------------------------------------------------------------------------
; A hook for Interrupt 15h (for future development)

 %if __Sample15
                ibm_isp _Multitask, Reset_MultiplexServ
  %if __SamplDrift
                cmp     ah, 83h
                je      @mt15VoidTimer
                cmp     ah, 86h
                je      @mt15VoidTimer
                jmp     SHORT @mt15Exit
@mt15VoidTimer:
                test    BYTE [@SpinFlag], 81h
                jnz     SHORT @mt15Exit
                pop     ebx
                popf
                push    ebx
                stc
                retf
  %endif
@mt15Exit:
                jmp     FAR [cs:_Multitask+2]
 %endif

; --------------------------------------------------------------------------
; Hook for Interrupt 2Fh (Multiplex Services)

;
; TSR Info Structure for Windows-aware TSR's and device drivers
;
struc	TSR_Info_Struc
   .TSR_Next:	resd	1     ; put ES:DI here and point ES:DI to struc
   .TSR_PSP_Segment:	resw	1     ; put CS here
   .TSR_API_Ver_ID:	resw	1  ; Set to 100h
   .TSR_Exec_Flags:	resw	1
   .TSR_Exec_Cmd_Show:	resw	1
   .TSR_Exec_Cmd:	resd	1
   .TSR_Reserved:	resb	4 
   .TSR_ID_Block:	resd	1
   .TSR_Data_Block:	resd	1
endstruc	;TSR_Info_Struc 

NoiseWin:
istruc	TSR_Info_Struc
iend
NoiseID:
                DW  IdLen
                DB  "NOISE.SYS", 0
IdLen		equ ($-NoiseID)-2

                ibm_isp _MultiplexServ
; Normally we'd call the original handler first, but in this case it
; interferes with values passed to and from orig. handler, so we check
; values passed first then jump.
                pushf

; <---- Add sampling of network (and CD-ROM?) calls to function 11h?

  %if __SamplCDROM
; Note: This does not work with SONY ATAPI_CD.SYS driver.
;       (Since I am using a SONY CD-ROM, I am unable to test this code)

                cmp     ah, 15h                 ; CD-ROM access (15h)?
                jne     SHORT @NoCD
                pushad                          ; save registers
                push    ds
                call    Sample
                pop     ds                      ; restore regs
                popad
                jmp     SHORT @QuitMServ
@NoCD:
  %endif
                cmp     ah, 16h                 ; Win broadcasts?
                jne     SHORT @QuitMServ
  %if 1
                cmp     al, 0Bh                 ; TSR ID?
                jne     SHORT @wc00
                mov     Word [NoiseWin], di
                mov     Word [NoiseWin+2], es
                mov     di, cs
                mov     es, di
                mov     di, NoiseWin
                jmp     SHORT @QuitMServ
@wc00:
  %endif
;
@ToggleWinFLag:
                cmp     al, 8                   ; Check for init/close msgs
                jb      SHORT @QuitMServ
                cmp     al, 9
                ja      SHORT @QuitMServ
                pushad
                push    ds
                xor     BYTE [Flags], WindowsFlag ; toggle flag
                jz      SHORT @NotInWin
;;  ifdef WIN95
;;  endif
@NotInWin:
  %if __SamplDrift
                mov     BYTE [@SpinFlag], 80h
  %endif
                call    Sample ; Sample enter/exit times for Windows...
                pop     ds
                popad
@QuitMServ:
                popf
                jmp     FAR [cs:_MultiplexServ+2]

; --------------------------------------------------------------------------
; A hook for Interrupt 21h (DOS)

  %if (__SamplExec) | (__SamplFlush)
;@LastExec       LABEL   WORD
;                DW      ?
  %endif
  %if (__DosSpinner) & (__Sample21 == 0)
@DosSpinner:
                DW      0
@LastDosSpin:
                DW      0
  %endif
                ibm_isp _NewInt21, Reset_MultiplexServ
  %if (__DosSpinner) & (__Sample21 == 0)
                inc     WORD [cs:@DosSpinner]
  ; ----- Count the number of calls to DOS between every clock tick
  %endif
  %if (__SamplExec) & (__Sample21 == 0)
                cmp     ah, 0             ; Old form of exit (still used)
                je      SHORT .SampleExec
                cmp     ah, 4Bh           ; Exec/Load overlay
                je      SHORT .SampleExec
                cmp     ah, 4Ch           ; Terminate process
                je      SHORT .SampleExec
  %endif
  %if (__SamplFlush) & (__Sample21 == 0)
                cmp     ah, 68h           ; Commit (flush) file
                je      SHORT .SampleExec
  %endif
  .OrigDOS:
  %ifn __Sample21
                jmp     FAR [cs:_NewInt21+2]
  %endif
  %if (__SamplExec) | (__SamplFlush) | (__Sample21)
  .SampleExec:
;; What this needs to do is set the InDOS flag?
;                pushf
;                cli
                pushad
                push    ds
                call    Sample
                pop     ds
                popad
;                popf
  %endif
                jmp     FAR [cs:_NewInt21+2]

