Metropoli BBS
VIEWER: pm24sh.asm MODE: TEXT (CP437)
; PMODE v2.4 shell for PMODE v3.0.
; By Tran (a.k.a. Thomas Pytel).

        .386p

LOWMIN          = 0             ; minimum free low memory (in K)
EXTMIN          = 0             ; minimum free extended memory (in K)
SELECTORS       = 8             ; extra selectors for allocation
STAKMAIN        = 100h          ; main execution stream stack size (in para)
STAKRMODE       = 10h           ; real mode call stack size (in para)
STAKPMODE       = 20h           ; protected mode call stack size (in para)
MODENESTING     = 8             ; max number of nested mode switches

RMODENUM        = (MODENESTING+1) shr 1
PMODENUM        = MODENESTING shr 1
STAKSIZE        = STAKMAIN+(PMODENUM*STAKPMODE)+(RMODENUM*STAKRMODE)

.errnz STAKSIZE gt 0fffh        ; error if stack greater than 64k

PMODE_TEXT      segment para public use16 'CODE'
PMODE_TEXT      ends
code16  segment para public use16
code16  ends
code32  segment para public use32
code32  ends
codeend segment para stack use32 'stack'
codeend ends

extrn   _pm_info:far, _pm_init:far
extrn   _pm_pagetables:byte, _pm_selectors:word, _pm_rmstacklen:word
extrn   _pm_pmstacklen:word, _pm_rmstacks:byte, _pm_pmstacks:byte
extrn   _pm_callbacks:byte

;▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓
; Real mode and 16bit code
;▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓
code16  segment para public use16
        assume cs:code16, ds:code16
        org 0

;▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒
; 16 bit common system data
;▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒
exiterrmsgtbl   dw      errmsg0,errmsg2,d_errmsg0,errmsg4,d_errmsg3,d_errmsg1

errmsg0         db      '386 or better not detected!!!',7,'$'
errmsg1         db      'Not enough low memory!!!',7,'$'
errmsg2         db      'System is already in V86 mode, and no VCPI or DPMI found!!!',7,'$'
errmsg3         db      'Not enough extended memory!!!',7,'$'
errmsg4         db      'Couldn''t enable A20 gate!!!',7,'$'
errmsg5         db      'Extended memory allocation failure. (weird eh???)',7,'$'

nullint         db      0cfh            ; IRET instruction
exitrout        dw      exit            ; exit routine, modified if XMS, VCPI
pmbuflen        dw      ?               ; length of PMODE low buffer

savedstakoff    dw      ?               ; current saved stack offset
savedstakseg    dw      ?               ; current saved stack segment

;▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒
; 16 bit common system code
;▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒
;═════════════════════════════════════════════════════════════════════════════
intreal:                                ; real mode int, load FS and GS here
        pushf
;-----------------------------------------------------------------------------
callreal:                               ; real mode call, load FS and GS here
        push cs
        push offset icreald
        mov fs,cs:v86r_fs
        mov gs,cs:v86r_gs
        mov eax,cs:v86r_eax
        mov ecx,cs:v86r_ecx
        mov edx,cs:v86r_edx
        mov ebx,cs:v86r_ebx
        mov esi,cs:v86r_esi
        mov edi,cs:v86r_edi
        mov ebp,cs:v86r_ebp
;-----------------------------------------------------------------------------
icreal:                                 ; real mode int, call, or IRQ
        db 66h,68h              ; PUSH destination addx
icrealm1        dd      ?       ;
icrealm0        db      ?       ; CLI or STI
        retf
;-----------------------------------------------------------------------------
icreald:                                ; done with real int or call
        cli
        pushf
        pop cs:v86r_flags
        mov cs:v86r_eax,eax
        mov cs:v86r_ecx,ecx
        mov cs:v86r_edx,edx
        mov cs:v86r_ebx,ebx
        mov cs:v86r_esi,esi
        mov cs:v86r_edi,edi
        mov cs:v86r_ebp,ebp
        mov cs:v86r_ds,ds
        mov cs:v86r_es,es
        mov cs:v86r_fs,fs
        mov cs:v86r_gs,gs
icreald2:
        mov ax,cs
        mov ds,ax
icrealm2        label word              ; return to pmode modifiable to JMP
;-----------------------------------------------------------------------------
        mov ebx,ds:dp_savedstakoff      ; DPMI return to pmode
        mov dx,ds:dp_savedstaksel
        mov edi,offset dp_int3_d
        mov si,ds:_selcode
        mov cx,dx
        mov ax,ds:_seldata
        jmp ds:d_switchaddx
;═════════════════════════════════════════════════════════════════════════════
int32:                                  ; real mode INT32: EDX=off
        pushad
        push ds es fs gs
        cli
        mov ax,cs
        mov ds,ax
        mov ds:p_cpmodem0,edx
        mov al,[esp+45]
        shr al,1
        and al,1
        add al,0fah
        mov ds:p_cpmodem1,al
        push savedstakoff
        push savedstakseg
        movzx ebx,ds:nextmodestack
        lea eax,[ebx-STAKPMODE*16]
        mov ds:nextmodestack,ax
        add ebx,ds:realstackbase
        mov savedstakseg,ss
int32m0         label   word            ; jump to pmode, modifiable
;-----------------------------------------------------------------------------
        sub sp,ds:dp_savelen
        mov savedstakoff,sp
        mov ax,ss                       ; DPMI jump to pmode
        mov es,ax
        mov di,sp
        xor al,al
        call d_saveaddx
        mov ax,ds:_seldata
        mov cx,ax
        mov dx,ax
        mov edi,offset p_cpmode0
        mov si,ds:_selcode
        jmp ds:d_switchaddx
;═════════════════════════════════════════════════════════════════════════════
int32d0:                                ; DPMI done with pmode call
        mov di,sp
        mov al,1
        call d_saveaddx
        add sp,ds:dp_savelen
;-----------------------------------------------------------------------------
int32d2:                                ; done from all
        pop savedstakseg
        pop savedstakoff
        add ds:nextmodestack,STAKPMODE*16
        mov bx,ds:v86r_flags
        mov ax,[esp+44]
        and ax,not 8d5h
        and bx,8d5h
        or ax,bx
        mov [esp+44],ax
        pop gs fs es ds
        popad
        iret
;─────────────────────────────────────────────────────────────────────────────
pregetlomem:                            ; Get low memory or abort
        add eax,ds:_lomembase
        mov ebx,ds:_lomemtop
        cmp eax,ebx
        ja short pregetlomema
        mov ecx,eax
        xchg eax,ds:_lomembase
        sub ebx,ecx
        cmp ebx,LOWMIN*1024
        jb short pregetlomema
        ret
pregetlomema:
        mov dx,offset errmsg1
;─────────────────────────────────────────────────────────────────────────────
exit16err:                              ; Exit program with message
        mov ah,9
        int 21h
        jmp exitrout
;-----------------------------------------------------------------------------
exit:                                   ; Guess what???
        mov ah,4ch
        mov al,ds:_exitcode
        int 21h
;═════════════════════════════════════════════════════════════════════════════
start16:                                ; Program begins here
        cli
        cld
        push cs
        pop ds

        push es                         ; set up PMODE variables
        mov ax,PMODE_TEXT
        mov es,ax
        mov es:_pm_pagetables,(EXTMIN+1024+4095)/4096
        mov es:_pm_selectors,3+SELECTORS
        mov es:_pm_rmstacklen,STAKRMODE
        mov es:_pm_rmstacks,MODENESTING/2
        xor eax,eax
        mov es:_pm_pmstacklen,ax
        mov es:_pm_pmstacks,al
        mov es:_pm_callbacks,al
        pop es

        call _pm_info                   ; get protected mode info
        mov si,ax
        mov dx,exiterrmsgtbl[si]
        jc exit16err                    ; if error, exit with error message

        mov pmbuflen,bx
        or ds:_sysbyte0,ch              ; set system type byte

        mov ax,es                       ; set up a bunch of pointers
        movzx eax,ax
        shl eax,4
        mov ds:_pspa,eax
        mov eax,code16
        shl eax,4
        mov ds:_code16a,eax
        or dword ptr ds:gdt32code16[2],eax
        or dword ptr ds:gdt32data16[2],eax
        mov ebx,code32
        shl ebx,4
        mov ds:_code32a,ebx
        or dword ptr ds:gdt32code32[2],ebx
        or dword ptr ds:gdt32data32[2],ebx
        mov eax,codeend
        shl eax,4
        sub eax,ebx
        mov ds:_lomembase,eax
        mov ds:realstackbase,eax
        movzx eax,word ptr es:[2]
        shl eax,4
        sub eax,ebx
        mov ds:_lomemtop,eax

        mov eax,STAKSIZE*16             ; get stack memory
        call pregetlomem

        push es                         ; save PSP seg (DPMI chek kills ES)
        pop fs

        jmp d_start

;─────────────────────────────────────────────────────────────────────────────
; BL=low PIC val, BH=high PIC val
setintslots:                            ; set int nums in table to PIC vals
        mov edi,offset ds:intslottbl
        mov cl,8
setintslotsl0:
        mov [di],bl
        inc di
        inc bl
        dec cl
        jnz setintslotsl0
        mov cl,8
setintslotsl1:
        mov [di],bh
        inc di
        inc bh
        dec cl
        jnz setintslotsl1
        ret

;▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒
; 16 bit DPMI system data
;▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒
d_errmsg0       db      'DPMI host is not 32bit!!!',7,'$'
d_errmsg1       db      'Ran out of DPMI descriptors!!!',7,'$'
d_errmsg2       db      'Couldn''t set DPMI descriptors as needed!!!',7,'$'
d_errmsg3       db      'Couldn''t enter 32bit protected mode!!!',7,'$'

d_memhandlep    db      0               ; 1=memory handle present, 0=not

d_enterpmode    dw      ?,?             ; DPMI switch to pmode addx
d_pspsel        dw      ?               ; stupid PSP selector
d_oldenvsegsel  dw      ?               ; stupid selector we dont want

d_memhandle     dw      ?,?             ; DPMI memory block handle

d_switchaddx    dd      ?               ; switch to pmode addx
d_saveaddx      dd      ?               ; save/restore state addx

d_nintoff       dd      offset dp_irq0,offset dp_irq1,offset dp_irq2,offset dp_irq3
                dd      offset dp_irq4,offset dp_irq5,offset dp_irq6,offset dp_irq7
                dd      offset dp_irq8,offset dp_irq9,offset dp_irqa,offset dp_irqb
                dd      offset dp_irqc,offset dp_irqd,offset dp_irqe,offset dp_irqf
                dd      offset dp_int33,offset dp_int32,offset dp_int33,offset dp_int32
;▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒
; 16 bit DPMI system code
;▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒
;═════════════════════════════════════════════════════════════════════════════
d_retreal:                              ; Return to real mode
        cmp d_memhandlep,0              ; free memory block if present
        je short d_retrealf0
        mov di,d_memhandle[0]
        mov si,d_memhandle[2]
        mov ax,502h
        int 31h
d_retrealf0:
        mov ax,205h                     ; restore all int vektorz needed
        mov edi,19
d_retreall0:
        mov bl,ds:intslottbl[edi]
        lea ebp,[edi*2+edi]
        mov edx,dword ptr ds:dp_ointbuf[ebp*2]
        mov cx,word ptr ds:dp_ointbuf[ebp*2+4]
        int 31h
        sub di,1
        jnc d_retreall0
        jmp short d_exit
;─────────────────────────────────────────────────────────────────────────────
d_exit16err:                            ; DPMI Exit with error message
        mov ds:v86r_ds,code16
        mov ds:v86r_ah,9
        mov ax,300h
        mov bx,21h
        xor cx,cx
        mov edi,offset ds:v86r_edi
        push ds
        pop es
        int 31h
;─────────────────────────────────────────────────────────────────────────────
d_exit:                                 ; DPMI exit to real mode
        mov es,d_pspsel                 ; restore env selector
        mov ax,d_oldenvsegsel
        mov es:[2ch],ax
        jmp exit
;═════════════════════════════════════════════════════════════════════════════
d_start:                                ; Start in a crappy DPMI system
        movzx eax,pmbuflen              ; get mem for DPMI low memory block
        shl eax,4
        call pregetlomem
        shr eax,4
        add ax,code32
        mov es,ax

        push word ptr fs:[2ch]          ; preserve environment segment

        call _pm_init                   ; switch to protected mode

        cli                             ; I don't trust myself
        mov dx,offset d_errmsg3
        jc exit16err
        mov ds:v86r_dx,offset d_errmsg1 ; prepare for abort maybe
        pop ax                          ; swap old env seg with selector
        xchg ax,es:[2ch]
        mov d_oldenvsegsel,ax
        mov d_pspsel,es                 ; store stupid selectors
        mov ds:data16sel,ds
        mov ds:code16sel,cs

        push ds                         ; no more need for PSP
        pop es
        mov ax,3                        ; get selector increment value
        int 31h
        mov bx,ax
        xor ax,ax                       ; get needed selectors
        mov cx,3+SELECTORS
        int 31h
        jc d_exit16err

        mov si,ax                       ; set up descriptors
        mov ds:_selcode,ax
        lea ecx,[eax+ebx]
        mov ds:_seldata,cx
        lea ebp,[ecx+ebx]
        mov ds:_selzero,bp
        lea eax,[ebp+ebx]
if SELECTORS ne 0
        mov ds:selectorbase,ax
        mov ds:selectorinc,bx
endif
        mov ds:v86r_dx,offset d_errmsg2

        mov ax,cs                       ; set DPL fields of descriptors
        lar ax,ax
        and ah,60h
        or byte ptr ds:gdt32code32[5],ah
        or byte ptr ds:gdt32data32[5],ah
        or byte ptr ds:gdt32zero32[5],ah

        mov ax,0ch                      ; set descriptors from GDT
        mov bx,si
        mov edi,offset ds:gdt32code32
        int 31h
        jc d_exit16err
        mov bx,cx
        mov edi,offset ds:gdt32data32
        int 31h
        jc d_exit16err
        mov bx,bp
        mov edi,offset ds:gdt32zero32
        int 31h
        jc d_exit16err
if SELECTORS ne 0
        mov bx,ds:selectorbase          ; set up extra allocatable selectors
        mov dx,SELECTORS
d_startl1:
        int 31h
        jc d_exit16err
        add bx,ds:selectorinc
        dec dx
        jnz d_startl1
endif
        mov es,cx                       ; ES, FS, and GS what they should be
        mov fs,cx
        mov gs,bp

        mov edi,ds:_lomembase           ; chek and get extended memory
        mov eax,ds:_lomemtop
        sub eax,edi
        cmp eax,48
        mov ds:v86r_dx,offset errmsg1
        jb d_exit16err
        mov ax,500h
        int 31h
        mov eax,es:[edi]
        lea edx,[eax+1024]
        mov ds:v86r_dx,offset errmsg3
d_startl2:
        sub edx,1024
        jnc short d_startf2
        xor edx,edx
d_startf2:
        cmp edx,EXTMIN*1024
        jb d_exit16err
        or edx,edx
        jz short d_startf1
        mov cx,dx
        shld ebx,edx,16
        mov ax,501h
        int 31h
        jc d_startl2
        mov ds:d_memhandle[0],di
        mov ds:d_memhandle[2],si
        mov ds:d_memhandlep,1

        shl ebx,16
        mov bx,cx
        sub ebx,ds:_code32a
        mov ds:_himembase,ebx
        add ebx,edx
        mov ds:_himemtop,ebx
d_startf1:

        mov ax,305h                     ; get save/restore state addxs
        int 31h
        mov ds:dp_savelen,ax
        mov dword ptr ds:dp_saveaddx[0],edi
        mov word ptr ds:dp_saveaddx[4],si
        mov word ptr d_saveaddx[0],cx
        mov word ptr d_saveaddx[2],bx
        mov ax,306h                     ; get switch mode addxs
        int 31h
        mov dword ptr ds:dp_switchaddx[0],edi
        mov word ptr ds:dp_switchaddx[4],si
        mov word ptr d_switchaddx[0],cx
        mov word ptr d_switchaddx[2],bx

        mov ax,400h                     ; set IRQ handlers to PIC values
        int 31h
        xchg dl,dh
        mov bx,dx
        call setintslots

        mov ah,2                        ; backup and set all int vektorz
        mov si,ds:_selcode
        mov edi,19
d_startl0:
        mov bl,ds:intslottbl[edi]
        mov al,4
        int 31h
        lea ebp,[edi*2+edi]
        mov dword ptr ds:dp_ointbuf[ebp*2],edx
        mov word ptr ds:dp_ointbuf[ebp*2+4],cx
        mov al,5
        mov edx,d_nintoff[edi*4]
        mov cx,si
        int 31h
        sub di,1
        jnc d_startl0

        mov ax,es                       ; set up needed regs & go on to 32bit
        mov ss,ax
        add esp,ds:realstackbase
        mov ds,ax
        push dword ptr cs:_selcode
        push offset p_start
        db 66h,0cbh             ; 32bit RETF

code16  ends

;▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓
; 32bit pmode code
;▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓
code32  segment para public use32
        assume cs:code32, ds:code32
        org 0

extrn   _main:near

public  _exit, _ret, _getmem, _getlomem, _gethimem, _lomemsize, _himemsize
public  _getirqmask, _setirqmask, _getselector, _freeselector, _rmpmirqset
public  _rmpmirqfree

public  v86r_eax, v86r_ebx, v86r_ecx, v86r_edx, v86r_esi, v86r_edi, v86r_ebp
public  v86r_ax, v86r_bx, v86r_cx, v86r_dx, v86r_si, v86r_di, v86r_bp
public  v86r_al, v86r_ah, v86r_bl, v86r_bh, v86r_cl, v86r_ch, v86r_dl, v86r_dh
public  v86r_ds, v86r_es, v86r_fs, v86r_gs
public  _selcode, _seldata, _selzero, _lomembase, _lomemtop, _himembase
public  _himemtop, _pspa, _code16a, _code32a, _getirqvect, _setirqvect
public  _sysbyte0, _irqmode, _setselector, _exitcode
;▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒
; 32 bit common system data
;▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒
_lomembase      dd      ?               ; low mem base for allocation
_lomemtop       dd      ?               ; top of low mem
_himembase      dd      0               ; high mem base for allocation
_himemtop       dd      0               ; top of high mem
_pspa           dd      ?               ; offset of start of PSP from 0
_code16a        dd      ?               ; offset of start of 16bit code from 0
_code32a        dd      ?               ; offset of start of 32bit code from 0
_selcode        dw      8               ; code segment selector
_seldata        dw      10h             ; data segment alias for code
_selzero        dw      18h             ; data segment starting at 0:0
_irqmode        dw      0ffffh          ; IRQ mode bits: 0=normal, 1=safe
                db      0ffh            ; misc byte, has to follow _irqmode
_sysbyte0       db      0               ; system bits:
                                        ;  0-1: 0=raw, 1=XMS, 2=VCPI, 3=DPMI
_exitcode       db      0               ; exit code for int21h ah=4ch

align 4
_getirqvect     dd      dp_getirqvect   ; get IRQ handler offset routine addx
_setirqvect     dd      dp_setirqvect   ; set IRQ handler offset routine addx
_setselector    dd      dp_setselector  ; set a selector addx offset addx

gdt32           dq      0
gdt32code32     db      0ffh,0ffh,0,0,0,9ah,0cfh,0
gdt32data32     db      0ffh,0ffh,0,0,0,92h,0cfh,0
gdt32zero32     db      0ffh,0ffh,0,0,0,92h,0cfh,0
gdt32code16     db      0ffh,0ffh,0,0,0,9ah,0,0
gdt32data16     db      0ffh,0ffh,0,0,0,92h,0,0
gdt32task       db      0ffh,0ffh,0,0,0,89h,0,0
gdt32vcpi       dq      3 dup(?)
if SELECTORS ne 0
gdt32free       db      SELECTORS dup(0ffh,0ffh,0,0,0,92h,0cfh,0)
endif

v86r_edi        label   dword           ; vregs for pmode<>real communication
v86r_di         dw      ?, ?            ;  needz to stay this way cuz its a
v86r_esi        label   dword           ;  stupid DPMI structure thingy
v86r_si         dw      ?, ?
v86r_ebp        label   dword
v86r_bp         dw      ?, ?
                dd      0
v86r_ebx        label   dword
v86r_bx         label   word
v86r_bl         db      ?
v86r_bh         db      ?, ?,?
v86r_edx        label   dword
v86r_dx         label   word
v86r_dl         db      ?
v86r_dh         db      ?, ?,?
v86r_ecx        label   dword
v86r_cx         label   word
v86r_cl         db      ?
v86r_ch         db      ?, ?,?
v86r_eax        label   dword
v86r_ax         label   word
v86r_al         db      ?
v86r_ah         db      ?, ?,?
v86r_flags      dw      ?
v86r_es         dw      ?
v86r_ds         dw      ?
v86r_fs         dw      ?
v86r_gs         dw      ?
                dd      0,0

oint1bvect      dd      ?               ; old real int 1bh vektor (ctrl+break)
oint32vect      dd      ?               ; old real int 32h vector
oirqmask        dw      ?               ; old port 21h and 0a1h masks
intslottbl      db      8,9,0ah,0bh,0ch,0dh,0eh,0fh,70h,71h,72h,73h,74h,75h,76h,77h
                db      35h,34h,33h,32h,31h,0,1,2,3,4,5,6,7,8,9,0ah,0bh,0ch,0dh,0eh

if SELECTORS ne 0
selectorbase    dw      50h
selectorinc     dw      8
selectorfree    db      SELECTORS dup(0)
endif

code16off       dw      d_retreal       ; offset in 16bit of exit function
code16sel       dw      20h             ; 16bit pmode code selector
data16sel       dw      28h             ; 16bit pmode data selector

nextmodestack   dw      (STAKSIZE-STAKMAIN)*16  ; stack for next mode switch
realstackbase   dd      ?               ; linear ptr to beginning of codeend

;▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒
; 32 bit common system code
;▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒
;═════════════════════════════════════════════════════════════════════════════
p_cpmode0:                              ; call pmode, load FS and GS
        mov fs,_seldata
        mov gs,_selzero
;-----------------------------------------------------------------------------
p_cpmode:                               ; call pmode routine from real
        push offset p_cpmoded
        cld
        mov eax,v86r_eax
        mov ecx,v86r_ecx
        mov edx,v86r_edx
        mov ebx,v86r_ebx
        mov esi,v86r_esi
        mov edi,v86r_edi
        mov ebp,v86r_ebp
        db 68h                  ; PUSH destination address
p_cpmodem0      dd      ?       ;
p_cpmodem1      db      ?       ; CLI or STI
        ret
;-----------------------------------------------------------------------------
p_cpmoded:                              ; call to pmode done
        cli
        pushf
        pop v86r_flags
        mov v86r_eax,eax
        mov v86r_ecx,ecx
        mov v86r_edx,edx
        mov v86r_ebx,ebx
        mov v86r_esi,esi
        mov v86r_edi,edi
        mov v86r_ebp,ebp
        mov ecx,_code16a
p_cpmodem2        label word            ; return to real, modifiable to JMP
;-----------------------------------------------------------------------------
        movzx ebx,gs:savedstakoff[ecx]  ; DPMI return to real mode
        mov dx,gs:savedstakseg[ecx]
        mov ax,code16
        mov cx,dx
        mov si,ax
        mov edi,offset int32d0
        jmp dp_switchaddx
;═════════════════════════════════════════════════════════════════════════════
p_start:                                ; common 32bit start
        mov eax,gs:[1bh*4]              ; neutralize crtl+break
        mov oint1bvect,eax
        db 65h,67h,0c7h,6       ; MOV DWORD PTR GS:[1bh*4],code16:nullint
        dw 1bh*4,nullint,code16 ;
        mov eax,gs:[32h*4]              ; set up for new real mode INT32
        mov oint32vect,eax
        db 65h,67h,0c7h,6       ; MOV DWORD PTR GS:[32h*4],code16:int32
        dw 32h*4,int32,code16   ;
        in al,21h                       ; save old PIC masks
        mov ah,al
        in al,0a1h
        mov oirqmask,ax
        jmp _main                       ; go to main code

;░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░
; Allocate any mem, (first cheks low, then high)
; In:
;   EAX - size requested
; Out:
;   CF=0 - memory allocated
;   CF=1 - not enough mem
;   EAX - linear pointer to mem or ?
;░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░
_getmem:
        push eax
        call _getlomem
        jnc short getmemd
        pop eax
        jmp short _gethimem
getmemd:
        add esp,4
_ret:                                   ; generic RET instruction
        ret
;░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░
; Allocate some low mem
; In:
;   EAX - size requested
; Out:
;   CF=0 - memory allocated
;   CF=1 - not enough mem
;   EAX - linear pointer to mem or ?
;░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░
_getlomem:
        add eax,_lomembase
        cmp eax,_lomemtop
        ja short getmemerr
        xchg eax,_lomembase
        clc
        ret
getmemerr:
        stc
        ret
;░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░
; Allocate some high mem
; In:
;   EAX - size requested
; Out:
;   CF=0 - memory allocated
;   CF=1 - not enough mem
;   EAX - linear pointer to mem or ?
;░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░
_gethimem:
        add eax,_himembase
        cmp eax,_himemtop
        ja short getmemerr
        xchg eax,_himembase
        clc
        ret
;░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░
; Get amount of free low mem
; Out:
;   EAX - number of bytes free
;░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░
_lomemsize:
        mov eax,_lomemtop
        sub eax,_lomembase
        ret
;░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░
; Get amount of free high mem
; Out:
;   EAX - number of bytes free
;░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░
_himemsize:
        mov eax,_himemtop
        sub eax,_himembase
        ret
;░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░
; Get status of IRQ mask bit
; In:
;   BL - IRQ num (0-15)
; Out:
;   AL - status: 0=enabled, 1=disabled
;░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░
_getirqmask:
        push ax
        in al,0a1h
        mov ah,al
        in al,21h
        xchg cl,bl
        shr ax,cl
        xchg cl,bl
        and al,1
        mov [esp],al
        pop ax
        ret
;░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░
; Set status of IRQ mask bit
; In:
;   BL - IRQ num (0-15)
;   AL - status: 0=enabled, 1=disabled
;░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░
_setirqmask:
        push ax bx cx dx
        mov cl,bl
        mov bx,0fffeh
        movzx dx,al
        rol bx,cl
        shl dx,cl
        in al,0a1h
        mov ah,al
        in al,21h
        and ax,bx
        or ax,dx
        out 21h,al
        mov al,ah
        out 0a1h,al
        pop dx cx bx ax
        ret
;░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░
; Set a real mode IRQ vect to redirect to pmode
; In:
;   BL - IRQ number
;   EDX - offset of IRQ handler
;   EDI -> 21 byte buffer for code stub created
; Out:
;   EAX - old seg:off of real mode IRQ handler
;░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░
rmpmirqsetd0:
db 66h,52h              ; PUSH EDX
db 66h,0bah,?,?,?,?     ; MOV EDX,?
db 0cdh,32h             ; INT 32h
db 66h,5ah              ; POP EDX
db 0cfh                 ; IRET
db 9ch                  ; PUSHFD
db 0eh                  ; PUSH CS
db 0e8h,?,?,?,?         ; CALL ?
db 0c3h                 ; RET
;-----------------------------------------------------------------------------
_rmpmirqset:
        push esi edi
        mov esi,offset rmpmirqsetd0
        lea eax,[edi+13]
        mov [esi+4],eax
        add eax,7
        sub eax,edx
        neg eax
        mov [esi+16],eax
        mov eax,edi
        movsd
        movsd
        movsd
        movsd
        movsd
        movsb
        add eax,_code32a
        shl eax,12
        shr ax,12
        movzx edi,bl
        cmp edi,8
        jb short rmpmirqsetf0
        add edi,60h
rmpmirqsetf0:
        xchg eax,gs:[edi*4+20h]
        pop edi esi
        ret
;░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░
; Reset a real more IRQ vect back to normal (just sets real mode IRQ vect)
; In:
;   BL - IRQ number
;   EAX - seg:off of real mode IRQ handler
;░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░
_rmpmirqfree:
        push ebx
        movzx ebx,bl
        cmp bl,8
        jb short rmpmirqfreef0
        add bl,60h
rmpmirqfreef0:
        mov gs:[ebx*4+20h],eax
        pop ebx
        ret
;░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░
; Allocate a selector
; Out:
;   CF=1 - selector not allocated
;   CF=0 - selector allocated
;   AX - 4G data selector or ?
; Notes:
;   The selector returned is for a 4G r/w data segment with an undefined base
;    address.
;░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░
_getselector:
if SELECTORS eq 0
        stc
        ret
else
        push ecx edi
        mov edi,offset selectorfree
        mov ecx,SELECTORS
        mov al,0
        repne scasb
        jne short getselectorf0
        mov byte ptr [edi-1],1
        sub ecx,SELECTORS-1
        neg ecx
        imul cx,selectorinc
        mov ax,selectorbase
        add ax,cx
        clc
        jmp short getselectorf1
getselectorf0:
        stc
getselectorf1:
        pop edi ecx
        ret
endif
;░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░
; Free an allocated selector
; In:
;   AX - selector
;░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░
_freeselector:
if SELECTORS ne 0
        push eax dx
        sub ax,selectorbase
        xor dx,dx
        div selectorinc
        movzx eax,ax
        mov selectorfree[eax],0
        pop dx eax
endif
        ret
;░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░
; Exit to real mode
;░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░
_exit:
        cli
        mov eax,oint1bvect              ; restore ctrl+break
        mov gs:[1bh*4],eax
        mov eax,oint32vect              ; restore real mode int 32h vector
        mov gs:[32h*4],eax
        mov ax,oirqmask                 ; restore PIC masks
        out 0a1h,al
        mov al,ah
        out 21h,al
        push code16sel                  ; go to 16bit pmode exit code
        push code16off
        mov ds,data16sel
        db 66h,0cbh             ; 16bit RETF

;▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒
; 32 bit DPMI system data
;▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒
dp_switchaddx   df      ?               ; switch to real mode addx
dp_saveaddx     df      ?               ; save/restore state addx
dp_savelen      dw      0,0             ; length of state buffer
dp_savedstakoff dd      ?               ; current saved stack offset
dp_savedstaksel dw      ?               ; current saved stack selector

dp_ointbuf      df      20 dup(?)       ; saved interrupt addx buffer
;▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒
; 32 bit DPMI system code
;▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒
;═════════════════════════════════════════════════════════════════════════════
dp_int32:                               ; DPMI INT32/34: CX:DX=seg:off
        pushad
        shl ecx,16
        mov cx,dx
        mov bp,offset callreal
        mov dl,1
        jmp short dp_int3_
;═════════════════════════════════════════════════════════════════════════════
dp_int33:                               ; DPMI INT33/35: AL=int num
        pushad
        movzx eax,al
        mov ecx,gs:[eax*4]
        mov bp,offset intreal
        xor dl,dl
;-----------------------------------------------------------------------------
dp_int3_:                               ; DPMI int or call to real mode
        mov ax,900h
        int 31h
        push ax
        and al,dl
        add al,0fah
        mov ebx,_code16a
        mov gs:icrealm0[ebx],al
        mov gs:icrealm1[ebx],ecx
        push dp_savedstakoff
        push dp_savedstaksel
        movzx ebx,nextmodestack
        lea eax,[ebx-STAKRMODE*16]
        mov nextmodestack,ax
        mov ax,ss
        mov es,ax
        sub esp,dword ptr dp_savelen
        mov edi,esp
        xor al,al
        call dp_saveaddx
        mov dp_savedstakoff,esp
        mov dp_savedstaksel,ss
        mov dx,codeend
        mov ax,v86r_ds
        mov cx,v86r_es
        movzx edi,bp
        mov si,code16
        jmp dp_switchaddx
;-----------------------------------------------------------------------------
dp_int3_d:                              ; done with real mode int or call
        mov edi,esp
        mov al,1
        call dp_saveaddx
        add esp,dword ptr dp_savelen
        pop dp_savedstaksel
        pop dp_savedstakoff
        add nextmodestack,STAKRMODE*16
        mov bx,v86r_flags
        pop ax
        int 31h
        mov ax,ds
        mov es,ax
        mov fs,ax
        mov gs,_selzero
        mov ax,[esp+40]
        and ax,not 8d5h
        and bx,8d5h
        or ax,bx
        mov [esp+40],ax
        popad
        iretd
;═════════════════════════════════════════════════════════════════════════════
; DPMI IRQ redirectors (needed to make all IRQ vector selectors = CS)
dp_irq0:
        jmp cs:dp_ointbuf[0]
dp_irq1:
        jmp cs:dp_ointbuf[6]
dp_irq2:
        jmp cs:dp_ointbuf[12]
dp_irq3:
        jmp cs:dp_ointbuf[18]
dp_irq4:
        jmp cs:dp_ointbuf[24]
dp_irq5:
        jmp cs:dp_ointbuf[30]
dp_irq6:
        jmp cs:dp_ointbuf[36]
dp_irq7:
        jmp cs:dp_ointbuf[42]
dp_irq8:
        jmp cs:dp_ointbuf[48]
dp_irq9:
        jmp cs:dp_ointbuf[54]
dp_irqa:
        jmp cs:dp_ointbuf[60]
dp_irqb:
        jmp cs:dp_ointbuf[66]
dp_irqc:
        jmp cs:dp_ointbuf[72]
dp_irqd:
        jmp cs:dp_ointbuf[78]
dp_irqe:
        jmp cs:dp_ointbuf[84]
dp_irqf:
        jmp cs:dp_ointbuf[90]

;░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░
; DPMI get IRQ handler offset
; In:
;   BL - IRQ num (0-0fh)
; Out:
;   EDX - offset of IRQ handler
;░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░
dp_getirqvect:
        push ax ebx cx
        movzx ebx,bl
        mov bl,intslottbl[ebx]
        mov ax,204h
        int 31h
        pop cx ebx ax
        ret
;░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░
; DPMI set IRQ handler offset
; In:
;   BL - IRQ num (0-0fh)
;   EDX - offset of IRQ handler
;░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░
dp_setirqvect:
        push ax ebx cx
        movzx ebx,bl
        mov bl,intslottbl[ebx]
        mov cx,cs
        mov ax,205h
        int 31h
        pop cx ebx ax
        ret
;░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░
; Set the base addx for a selector
; In:
;   AX - selector
;   EDX - linear base addx for selector
;░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░
dp_setselector:
if SELECTORS ne 0
        push ax bx ecx
        shld ecx,edx,16
        mov bx,ax
        mov ax,7
        int 31h
        pop ecx bx ax
endif
        ret

code32  ends

;▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓
; End of program (must be at end of program or you will suffer)
;▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓
codeend segment para stack use32 'stack'
db STAKSIZE*16 dup(?)
codeend ends
        end     start16

[ RETURN TO DIRECTORY ]