;*      DPMI.ASM
;*
;* DPMI functions for protected mode MIDAS
;*
;* $Id: dpmi.asm,v 1.2 1996/08/04 11:14:32 pekangas Exp $
;*
;* Copyright 1996 Petteri Kangaslampi and Jarno Paananen
;*
;* This file is part of the MIDAS Sound System, and may only be
;* used, modified and distributed under the terms of the MIDAS
;* Sound System license, LICENSE.TXT. By continuing to use,
;* modify or distribute this file you indicate that you have
;* read the license and understand and accept it fully.
;*

P386
IDEAL
JUMPS


INCLUDE "lang.inc"
INCLUDE "errors.inc"
INCLUDE "dpmi.inc"



CODESEG



;/***************************************************************************\
;*
;* Function:    int dpmiAllocDescriptor(unsigned *descriptor);
;*
;* Description: Allocate LDT descriptor. Use dpmiFreeDescriptor to deallocate.
;*
;* Input:       unsigned *descriptor    pointer to descriptor number
;*
;* Returns:     MIDAS error code. Descriptor number is written to *descriptor.
;*
;\***************************************************************************/

PROC    dpmiAllocDescriptor     _funct  descriptor : _ptr
USES    _bx

        xor     _ax,_ax                 ; DPMI function 0 - alloc LDT descr.
        mov     _cx,1                   ; allocate one descriptor
        int     31h
        jc      @@err

IFDEF __32__
        and     eax,0FFFFh
ENDIF

        LOADPTR es,_bx,[descriptor]     ; write allocated descriptor to
        mov     [_esbx],_ax             ; *descriptor

        xor     _ax,_ax
        jmp     @@done

@@err:
        mov     _ax,errDPMIFailure
        ERROR   ID_dpmiAllocDescriptor

@@done:
        ret
ENDP




;/***************************************************************************\
;*
;* Function:    int dpmiFreeDescriptor(unsigned descriptor);
;*
;* Description: Deallocates an LDT descriptor.
;*
;* Input:       unsigned descriptor     descriptor to deallocate
;*
;* Returns:     MIDAS error code
;*
;\***************************************************************************/

PROC    dpmiFreeDescriptor      _funct  descriptor : _int
USES    _bx

        mov     _ax,0001h               ; DPMI function 1 - free LDT descr.
        mov     _bx,[descriptor]
        int     31h
        jc      @@err

        xor     _ax,_ax
        jmp     @@done

@@err:
        mov     _ax,errInvalidDescriptor
        ERROR   ID_dpmiFreeDescriptor

@@done:
        ret
ENDP




;/***************************************************************************\
;*
;* Function:    int dpmiSetSegmentBase(unsigned selector, ulong baseAddr);
;*
;* Description: Changes the 32-bit linear base address of a selector.
;*
;* Input:       unsigned selector       selector number
;*              ulong baseAddr          32-bit linear base address for
;*                                      selector
;*
;* Returns:     MIDAS error code.
;*
;\***************************************************************************/

PROC    dpmiSetSegmentBase      _funct  selector : _int, baseAddr : _long
USES    _bx

        mov     _ax,0007h               ; DPMI function 7 - set segment base
        mov     _bx,[selector]
IFDEF __32__
        xor     ecx,ecx
        xor     edx,edx
ENDIF
        mov     cx,[word baseAddr+2]    ; cx:dx = new base address
        mov     dx,[word baseAddr]
        int     31h
        jc      @@err

        xor     _ax,_ax
        jmp     @@done

@@err:
        mov     _ax,errInvalidDescriptor
        ERROR   ID_dpmiSetSegmentBase

@@done:
        ret
ENDP




;/***************************************************************************\
;*
;* Function:    int dpmiGetSegmentBase(unsigned selector, ulong *baseAddr);
;*
;* Description: Reads the 32-bit linear base address of a selector.
;*
;* Input:       unsigned selector       selector number
;*              ulong *baseAddr         pointer to the 32-bit linear base
;*                                      address of the selector
;*
;* Returns:     MIDAS error code. Selector base address is written to
;*              *baseAddr.
;*
;\***************************************************************************/

PROC    dpmiGetSegmentBase      _funct  selector : _int, baseAddr : _ptr
USES    _bx

        mov     _ax,0006h               ; DPMI function 7 - get segment base
        mov     _bx,[selector]
        int     31h
        jc      @@err

        LOADPTR es,_bx,[baseAddr]
        mov     [word _esbx],dx         ; write segment base address to
        mov     [word _esbx+2],cx       ; *baseAddr

        xor     _ax,_ax
        jmp     @@done

@@err:
        mov     _ax,errInvalidDescriptor
        ERROR   ID_dpmiGetSegmentBase

@@done:
        ret
ENDP




;/***************************************************************************\
;*
;* Function:    int dpmiSetSegmentLimit(unsigned selector, ulong limit);
;*
;* Description: Changes the limit of a segment selector.
;*
;* Input:       unsigned selector       selector number
;*              ulong limit             32-bit segment limit
;*
;* Returns:     MIDAS error code.
;*
;\***************************************************************************/

PROC    dpmiSetSegmentLimit     _funct  selector : _int, limit : _long
USES    _bx

        mov     _ax,0008h               ; DPMI function 8 - set segment limit
        mov     _bx,[selector]
IFDEF __32__
        xor     ecx,ecx
        xor     edx,edx
ENDIF
        mov     cx,[word limit+2]       ; cx:dx = new segment limit
        mov     dx,[word limit]
        int     31h
        jc      @@err

        xor     _ax,_ax
        jmp     @@done

@@err:
        mov     _ax,errDPMIFailure
        ERROR   ID_dpmiSetSegmentLimit

@@done:
        ret
ENDP




;/***************************************************************************\
;*
;* Function:    int dpmiSetSegmentAccessRights(unsigned selector,
;*                  unsigned accessRights);
;*
;* Description: Changes the access rights of a selector
;*
;* Input:       unsigned selector       selector
;*              unsigned accessRights   new access rights for the segment
;*
;* Returns:     MIDAS error code.
;*
;\***************************************************************************/

PROC    dpmiSetSegmentAccessRights      _funct  selector : _int, \
                                                accessRights : _int
USES    _bx

        mov     _ax,0009h               ; DPMI function 9 - set access rights
        mov     _bx,[selector]
        mov     _cx,[accessRights]
        int     31h
        jc      @@err

        xor     _ax,_ax
        jmp     @@done

@@err:
        mov     _ax,errDPMIFailure
        ERROR   ID_dpmiSetSegmentAccessRights

@@done:
        ret
ENDP




;/***************************************************************************\
;*
;* Function:    int dpmiCreateCodeAlias(unsigned codeSelector,
;*                  unsigned *selector);
;*
;* Description: Creates a data descriptor that has the same base and limit
;*              as a code segment descriptor. Use dpmiFreeDescriptor() to
;*              deallocate data descriptor.
;*
;* Input:       unsigned codeSelector   code segment selector
;*              unsigned *selector      pointer to data segment selector
;*
;* Returns:     MIDAS error code. New data selector is written to *selector.
;*
;\***************************************************************************/

PROC    dpmiCreateCodeAlias     _funct  codeSelector : _int, selector : _ptr
USES    _bx

        mov     _ax,000Ah               ; 000Ah - create code alias descr.
        mov     _bx,[codeSelector]
        int     31h
        jc      @@err

IFDEF __32__
        and     eax,0FFFFh
ENDIF

        LOADPTR es,_bx,[selector]       ; write selector to *selector
        mov     [_esbx],_ax

        xor     _ax,_ax
        jmp     @@done

@@err:
        mov     _ax,errDPMIFailure
        ERROR   ID_dpmiCreateCodeAlias

@@done:
        ret
ENDP




;/***************************************************************************\
;*
;* Function:    int dpmiAllocDOSMem(unsigned numParagraphs, unsigned *segment,
;*                  unsigned *selector);
;*
;* Description: Allocates memory from DOS free memory pool, below 1MB. Use
;*              dpmiFreeDOSMem() to deallocate.
;*
;* Input:       unsigned numParagraphs  number of paragraphs to allocate
;*              unsigned *segment       pointer to real mode segment
;*              unsigned *selector      pointer to selector
;*
;* Returns:     MIDAS error code. Real mode segment of allocated block is
;*              written to *segment. Protected mode selector for block is
;*              written to *selector.
;*
;\***************************************************************************/

PROC    dpmiAllocDOSMem         _funct  numParagraphs : _int, \
                                        realSeg : _ptr, selector : _ptr
USES    _bx

        mov     _ax,0100h               ; 0100h - alloc DOS memory block
        mov     _bx,[numParagraphs]
        int     31h
        jnc     @@ok

        cmp     _ax,07h                 ; memory control blocks damaged?
        je      @@mcbDamaged
        cmp     _ax,08h                 ; insufficient memory?
        je      @@nomemory

        mov     _ax,errDPMIFailure
        jmp     @@err

@@mcbDamaged:
        mov     _ax,errHeapCorrupted
        jmp     @@err

@@nomemory:
        mov     _ax,errOutOfMemory
        jmp     @@err

@@ok:
IFDEF __32__
        and     eax,0FFFFh
        and     edx,0FFFFh
ENDIF
        LOADPTR es,_bx,[realSeg]
        mov     [_esbx],_ax             ; write real mode segment to *segment
        LOADPTR es,_bx,[selector]
        mov     [_esbx],_dx             ; write selector to *selector

        xor     _ax,_ax
        jmp     @@done

@@err:
        ERROR   ID_dpmiAllocDOSMem

@@done:
        ret
ENDP




;/***************************************************************************\
;*
;* Function:    dpmiFreeDOSMem(unsigned selector);
;*
;* Description: Deallocates memory allocated with dpmiAllocDOSMem().
;*
;* Input:       unsigned selector       selector for allocated block
;*
;* Returns:     MIDAS error code
;*
;\***************************************************************************/

PROC    dpmiFreeDOSMem          _funct  selector : _int
USES    _bx

        mov     _ax,0101h               ; 0101h - free DOS memory block
        mov     _dx,[selector]
        int     31h
        jc      @@error

        xor     _ax,_ax
        jmp     @@done

@@error:
        cmp     _ax,07h                 ; memory control blocks damaged?
        je      @@mcbDamaged
        cmp     _ax,09h                 ; incorrect segment?
        je      @@badSegment

        mov     _ax,errDPMIFailure
        jmp     @@err

@@mcbDamaged:
        mov     _ax,errHeapCorrupted
        jmp     @@err

@@badSegment:
        mov     _ax,errInvalidDescriptor

@@err:
        ERROR   ID_dpmiFreeDOSMem

@@done:
        ret
ENDP




;/***************************************************************************\
;*
;* Function:    int dpmiRealModeInt(unsigned intNum,
;*                  dpmiRealCallRegs *registers);
;*
;* Description: Simulates a real mode interrupt using DPMI service 0x0300.
;*              *register MUST contain appropriate register values for
;*              interrupt (CS:IP is ignored).
;*
;* Input:       unsigned intNum                 interrupt number
;*              dpmiRealCallRegs *registers     DPMI real mode calling struct
;*
;* Returns:     MIDAS error code. Register values returned by the interrupt
;*              are written to *registers.
;*
;\***************************************************************************/

PROC    dpmiRealModeInt         _funct  intNum : _int, registers : _ptr
USES    _di,es,_bx

IFDEF __32__
        mov     ax,ds
        mov     es,ax
        xor     ebx,ebx
        xor     ecx,ecx
ELSE
        xor     cx,cx
ENDIF

        mov     _ax,0300h               ; 0300h - simulate real mode interrupt
        mov     bl,[byte intNum]
        mov     bh,1                    ; reset PIC and A20 line
        LOADPTR es,_di,[registers]
        int     31h
        jc      @@err

        ; es:_di now contains pointer to modified real mode call structure.
        ; The DPMI specs do not clearly state that this is necessarily the
        ; same as the original structure, so for safety we check the pointers
        ; and if they differ copy the data to the original structure:

IFDEF __32__
        mov     ax,es
        mov     dx,ds
        cmp     ax,dx
        jne     @@copyregs
        cmp     edi,[registers]
        jne     @@copyregs
ELSE
        mov     ax,es
        cmp     ax,[word registers+2]
        jne     @@copyregs
        cmp     di,[word registers]
        jne     @@copyregs
ENDIF

        ; es:di points to the original structure - the new register values
        ; are at their place.

        xor     _ax,_ax
        jmp     @@done

@@copyregs:
        ; es:_di has changed - copy the new register structure to the old
        ; place:
        push    ds _si

        mov     _si,_di

IFDEF __32__
        mov     ax,es
        mov     dx,ds
        mov     ds,ax
        mov     es,dx
ELSE
        mov     ax,es                   ; ds:_si = es:_di
        mov     ds,ax
ENDIF
        LOADPTR es,_di,[registers]
        mov     _cx,SIZE dpmiRealCallRegs
        cld
        rep     movsb

        pop     _si ds

        xor     _ax,_ax
        jmp     @@done

@@err:
        mov     _ax,errDPMIFailure
        ERROR   ID_dpmiRealModeInt

@@done:
        ret
ENDP




;/***************************************************************************\
;*
;* Function:    int dpmiLockMemory(ulong start, ulong numBytes);
;*
;* Description: Locks a region of memory to prevent it from being paged. The
;*              memory can be unlocked using dpmiUnlockMemory().
;*
;* Input:       ulong start             memory region start address
;*              ulong numBytes          memory region length in bytes
;*
;* Returns:     MIDAS error code
;*
;\***************************************************************************/

PROC    dpmiLockMemory          _funct  start : _long, numBytes : _long
USES    _si,_di, _bx

        mov     _ax,0600h               ; 0600h - Lock Linear Region

IFDEF __32__
        xor     ebx,ebx
        xor     ecx,ecx
        xor     esi,esi
        xor     edi,edi
ENDIF

        mov     bx,[word start+2]       ; bx:cx = start address
        mov     cx,[word start]
        mov     si,[word numBytes+2]    ; si:di = number of bytes
        mov     di,[word numBytes]

        int     31h
        jc      @@err

        xor     _ax,_ax
        jmp     @@done

@@err:
        mov     _ax,errDPMIFailure
        ERROR   ID_dpmiLockMemory

@@done:
        ret
ENDP




;/***************************************************************************\
;*
;* Function:    int dpmiUnlockMemory(ulong start, ulong numBytes);
;*
;* Description: Unlocks a region of memory locked with dpmiLockMemory().
;*
;* Input:       ulong start             memory region start address
;*              ulong numBytes          memory region length in bytes
;*
;* Returns:     MIDAS error code
;*
;\***************************************************************************/

PROC    dpmiUnlockMemory        _funct  start : _long, numBytes : _long
USES    _si,_di,_bx

        mov     _ax,0600h               ; 0601h - Unlock Linear Region

IFDEF __32__
        xor     ebx,ebx
        xor     ecx,ecx
        xor     esi,esi
        xor     edi,edi
ENDIF

        mov     bx,[word start+2]       ; bx:cx = start address
        mov     cx,[word start]
        mov     si,[word numBytes+2]    ; si:di = number of bytes
        mov     di,[word numBytes]

        int     31h
        jc      @@err

        xor     _ax,_ax
        jmp     @@done

@@err:
        mov     _ax,errDPMIFailure
        ERROR   ID_dpmiUnlockMemory

@@done:
        ret
ENDP



;* $Log: dpmi.asm,v $
;* Revision 1.2  1996/08/04 11:14:32  pekangas
;* All functions now preserve _bx
;*
;* Revision 1.1  1996/05/22 20:49:33  pekangas
;* Initial revision
;*


END