[TulaAnti&ViralClub] PRESENTS ...
MooN_BuG, Issue 7, Sep 1998                                           file 013

                               DPMI из под DOS
                                              by Quarterdeck Office Systems

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;
;; DPMI Demonstration Program.
;; (C) Copyright 1992, Quarterdeck Office Systems.
;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
        name    DPMI
        title   DPMI Demo Program

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;
;; CODE STARTS HERE.  Define Code Segment as usual.
;; We will be using 16 bit segments.
;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
d_seg segment 'code'
        assume  cs:d_seg,ds:d_seg

        org     100h

entry_point:
        jmp     main

;
; Local Data Alloctions.
;
DPMIEntryPoint          dd      ?       ; REAL far address for Switch Entry.
FreeSeg                 dw      ?       ; first free segment above program.
PrivateDataSeg          dw      ?       ; segment of allocated memory for DPMI
SegsRequired            dw      ?       ; number segs required by DPMI host.
VideoPad                dw      ?       ; Possibly DESQview virtualized video
ScreenSel               dw      ?       ; Selector for access to video.
DataSel                 dw      ?       ; Selector for data segment

MemErrorMessage         db      'Not enough memory to run',13,10,'$'
DPMIErrorMessage        db      'DPMI is not present.',13,10,'$'

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;
;; GetScreenSel
;; ============
;;
;; Args:        none
;;
;; Returns:     cy=0:   ax = selector mapped to video screen.
;;              cy=1:   FAILURE
;;
;; Description: Get a valid data selector pointing to video screen.
;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
GetScreenSel proc
        push    bx

        mov     ax, 0002h               ; DPMI: Segment to Descriptor
        mov     bx, VideoPad            ; We want to point at video pad
        int     31h                     ; Call DPMI.  (cy=1 if error)

        pop     bx
        ret
GetScreenSel endp

title_mark label byte
        db
'╔═════════════════════════════════════════════════════════════════════════════
═╗'
        db      '║                ║'
        db      '║                ║'
        db      '║                ║'
        db      '║   DDDDDDDD         PPPPPPPPPPPP       MMMMMM MMMMMMM IIIIII
║'
        db      '║    DDDD  DDD        PPPP      PPP      MMMMMMM      MMMMMMMM
IIII      ║'
        db      '║    DDDD    DDD      PPPP       PPP     MMMM  MMM   MMM  MMMM
IIII      ║'
        db      '║    DDDD    DDDD     PPPP       PPP     MMMM   MMM MMM   MMMM
IIII      ║'
        db      '║    DDDD      DDD    PPPP       PPP     MMMM     MMMM    MMMM
IIII      ║'
        db      '║    DDDD      DDD    PPPP      PPP      MMMM     MMMM    MMMM
IIII      ║'
        db      '║    DDDD      DDD    PPPPPPPPPPP        MMMM             MMMM
IIII      ║'
        db      '║    DDDD    DDD      PPPP               MMMM             MMMM
IIII      ║'
        db      '║    DDDD    DDD      PPPP               MMMM             MMMM
IIII      ║'
        db      '║    DDDD  DDD        PPPP               MMMM             MMMM
IIII      ║'
        db      '║   DDDDDDDD         PPPPPP             MMMMMM MMMMMM   IIIIII
║'
        db      '║                ║'
        db      '║                This is a Dos Protected Mode Interface DEMO
║'
        db      '║                ║'
        db
'╚═════════════════════════════════════════════════════════════════════════════
═╝'
end_title label byte

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;
;; ProtModeRoutine
;; ===============
;;
;; Args:        None.
;;
;; Returns:     nothing.
;;
;; Description: This is called from PROTECTED mode (after VCPI switch into
;;              PROTECTED mode), and displays the single character '!' in
;;              the upper-left corner of the display.  It uses the selector
;;              previously setup for accessing the virtual video PAD buffer.
;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
ProtModeRoutine proc
        push    ax
        push    cx
        push    di
        push    es

        cld

;
; Set up pointer to video.
;
        mov     ax,ScreenSel
        mov     es,ax
        xor     di, di                  ; es:di -> Video Screen.
        mov     ah, 17h
        mov     cx, offset end_title - offset title_mark
        mov     si, offset title_mark

pmr_loop:
        lodsb
        stosw
        loop    pmr_loop

        pop     es
        pop     di
        pop     cx
        pop     ax
        ret
ProtModeRoutine endp

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;
;; GetScreenSeg
;; ============
;;
;; Args:        none
;;
;; Returns:     ax -> DESQview virtualized video PAD.
;;
;; Description: Get possibly virtualized video PAD for direct writes to
;;              screen.
;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
GetScreenSeg proc
        push    di
        push    es

        xor     ax,ax                   ; es -> low 64K real segment
        mov     es,ax

        mov     ax,0b000h               ; assume mono
        cmp     byte ptr es:[449h],7    ; Mono?
        je      gss_dv_call

        mov     ax,0b800h               ; Color.

gss_dv_call:
        mov     es,ax                   ; es -> video segment for BIOS call
        mov     ah,0feh                 ; get video PAD address
        int     10h                     ; Modifies ES:DI
        mov     ax,es                   ; return segment in ax

        pop     es
        pop     di
        ret
GetScreenSeg endp

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;
;; AllocatePrivateData
;; ===================
;;
;; Args:        none.
;;
;; Returns:     cy=0:   Memory successfully allocated
;;              cy=1:   FAILURE: no memory available for DPMI private data.
;;
;; Description: Allocate DPMI's private data area based on value in the
;;              variable SegsRequired, as set up by the procedure IsDPMI.
;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
AllocatePrivateData proc
;
; As a .COM program, we have all available conventional memory allocated to
; us by DOS.  Reduce this requirement to our minimum value.
;
        mov     bx,FreeSeg              ; get the first segment free above us.
        mov     ax,ds                   ; get the base of our code/data.
        sub     bx,ax                   ; bx = number of paragraphs required.
        mov     es,ax                   ; prepare for modify memory block call
        mov     ah,4ah                  ; DOS: Modify Memory Block
        int     21h                     ; Shrink to our minimum
        jc      apd_err                 ; Failure.

;
; We have returned unneeded memory back to DOS.  Now allocate what DPMI has
; told us it requires.
;
        mov     bx,SegsRequired         ; get number of paragraphs required
        test    bx,bx                   ; if none, just return success.
        jz      apd_done
;
; Allocate private data area from DOS.
;
        mov     ah,48h                  ; DOS: Allocate Memory.
        int     21h
        jc      apd_err                 ; Failure.

;
; Memory was successfully allocated.  Save the segment for when we switch
; into PROTECTED mode.
;
        mov     PrivateDataSeg,ax

apd_done:
        clc                             ; return success.
        ret

apd_err:
        stc                             ; return failure.
        ret
AllocatePrivateData endp

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;
;; IsDPMI
;; ======
;;
;; Args:        none.
;;
;; Returns:     cy=0:           DPMI Host is present.
;;              DPMIEntryPoint: Set to V86 (or REAL) mode far address to call
;;                              to cause the initial switch to PROTECTED mode.
;;              SegsRequired:   Set to the number of 16 byte paragraphs
;;                              required by DPMI Host for its private data
;;                              area.
;;
;;              cy=1:           FAILURE! DPMI host is not present.
;;
;; Description: Determines whether a DPMI host is present, and if so, saves
;;              both the V86 (or REAL) mode far address to call to switch to
;;              protected mode, as well as the number of paragraphs of memory
;;              required by the DPMI host for its private data area.
;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
IsDPMI proc
;
; Check to be sure INT 2Fh vector is not NULL.
;
        mov     ax,352fh
        int     21h
        mov     ax,es
        or      ax,bx
        jz      id_no_dpmi                      ; if NULL, no DPMI host.

;
; Use the DPMI: Obtain Switch Entry Point call to determine if DPMI host
; is present.
;
        mov     ax,1687h
        int     2fh
        test    ax,ax
        jnz     id_no_dpmi                      ; if ax != 0, no DPMI host.

;
; There is a DPMI host present.  Save its Switch Entry address, and its
; memory requirements, and return.
;
        mov     word ptr DPMIEntryPoint,di
        mov     word ptr DPMIEntryPoint+2,es
        mov     SegsRequired,si

        clc                                     ; return success.
        ret

id_no_dpmi:
        stc                                     ; return failure.
        ret
IsDPMI endp

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;
;; main
;; ====
;;
;; Args:        ds = segment of PSP
;;              es = segment of PSP
;;              cs = segment of PSP
;;
;; Returns:
;;
;; Description:
;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
main proc
        cld                             ; set string moves forward.

;
; "Allocate" memory above program image for initial stack, and
; save segment to free memory.
;
--- GEd: Водка кончилась, началась чистая правда. +++
 * Origin: ...в ожидании Солнца... Dark Lazy MW BBS, Penza 63-02-4 (2:5059/9.5)

─ Echo From 2:5022/12.0 (2:5022/12.23) ──────────────────────────── TALKS.ASM ─
 Msg  : 16583 из 16584
 From : Alexey Tyurin                       2:5059/9.5      Втр 28 Июл 98 18:10
 To   : Sergey Mishin                                       Втр 28 Июл 98 22:25
 Subj : 2 Re: DPMI
───────────────────────────────────────────────────────────────────────────────
        mov     si,offset end_of_program+500
        lea     ax,[si+15]              ; si -> past top of local stack
        mov     cl,4                    ; convert address to segment
        shr     ax,cl
        mov     bx,cs
        add     ax,bx                   ; ax = first free segment past code.
        mov     FreeSeg,ax
        cmp     ax,ds:[2]               ; check to see that there is free mem.
        jae     short m_out_of_mem      ; .. nope.. failure.

;
; Set-up stack
;
        mov     sp,si                   ; sp -> top of stack
        call    IsDPMI                  ; check for DPMI support
        jc      short m_no_dpmi         ; no DPMI, quit with message.

;
; Determine segment of video buffer (PAD)
;
        call    GetScreenSeg            ; ax = segment of video pad.
        mov     VideoPad, ax            ;

;
; Using return value of si (Number of paragraphs required by DPMI to switch
; into PROTECTED mode), allocate DPMI's private data area.
;
        call    AllocatePrivateData     ; si = number of 16 byte paragraphs
        jc      short m_out_of_mem      ; out of memory error.

;
; Set up registers for switch into protected mode:
;
; ax = flags.
; es = RM segment of DPMI private data area.
;
        mov     es,PrivateDataSeg       ; es = segment of DPMI private data
        xor     ax,ax                   ; Initialize as a 16-bit application
        call    DPMIEntryPoint          ; Switch into protected mode!

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;
;; WE ARE NOW IN PROTECTED MODE!
;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;
; Get selector to access video memory directly.
;
        call    GetScreenSel            ;
        jc      m_no_dpmi               ; ERROR...

        mov     ScreenSel, ax           ; save selector for "work" routines.
;
; Ok, now for the exciting part.
;
        call    ProtModeRoutine         ; Do our "thang..."

;
; NOTE: No need to return to V86 (or REAL) mode to exit program, as with VCPI.
;
        mov     ax,4c00h
        int     21H

;
; Various ERROR exit points: display message and then exit.
;
; OUT OF MEMORY
;
m_out_of_mem:
        mov     dx,offset MemErrorMessage
m_err:
        mov     ah,9
        int     21H
        mov     ax,4c01h
        int     21h

;
; NO DPMI
;
m_no_dpmi:
        mov     dx,offset DPMIErrorMessage
        jmp     m_err
main endp

        even
end_of_program  label byte

d_seg   ends
        end     entry_point