PAGE ,132 TITLE Windows Protect Mode Routines .xlist include kernel.inc .386p include protect.inc include pdb.inc .list ifdef WOW ; ; the dpmi func 04f1h is idential to function 00h, except that ; the descriptor base and limit are not initialized to zero. ; ; ; the dpmi func 04f2h is identical to 0ch except that it ; sets 'count' (in cx) LDTs at one time. The first selector is in ; register bx. The descriptor data is in gdtdsc[bx], gdtdsc[bx+8] ; etc. This data is shared between dpmi (dosx.exe) and us and thus ; need not be passed in es:di WOW_DPMIFUNC_00 equ 04f1h WOW_DPMIFUNC_0C equ 04f2h endif MovsDsc Macro ;Move (copy) a descriptor (4 words) cld movsd movsd endm CheckDS Macro local okds if KDEBUG push ax mov ax, ds SetKernelDS cmp ax, ArenaSel mov ds, ax UnSetKernelDS je short okds int 3 int 3 okds: pop ax endif endm CheckLDT Macro selector if KDEBUG test selector,SEL_LDT jnz short @F int 3 @@: endif Endm DPMICALL MACRO callno mov ax, callno call DPMIProc ENDM MY_SEL equ 0F00h ; Access word to indicate selector owned by kernel externW pLocalHeap DataBegin ifdef WOW externW SelectorFreeBlock externW UserSelArray externB fBooting globalW high0c,0 globalD FlatAddressArray,0 endif externW MyCSSeg externW WinFlags externW ArenaSel externW pGlobalHeap externW MyCSAlias extrn kr1dsc:WORD extrn kr2dsc:WORD extrn blotdsc:WORD extrn DemandLoadSel:WORD extrn FreeArenaList:DWORD extrn FreeArenaCount:DWORD extrn HighestArena:DWORD extrn temp_arena:DWORD extrn SelTableLen:word extrn SelTableStart:DWORD extrn temp_sel:WORD extrn FirstFreeSel:WORD extrn CountFreeSel:WORD if ROM externW selROMTOC externW selROMLDT externW sel1stAvail endif if ROM externD lmaHiROM externD cbHiROM externD linHiROM endif DataEnd DataBegin INIT RModeCallStructure STRUC RMCS_EDI dd 0 RMCS_ESI dd 0 RMCS_EBP dd 0 RMCS_Res dd 0 RMCS_EBX dd 0 RMCS_EDX dd 0 RMCS_ECX dd 0 RMCS_EAX dd 0 RMCS_Flags dw 0 RMCS_ES dw 0 RMCS_DS dw 0 RMCS_FS dw 0 RMCS_GS dw 0 RMCS_IP dw 0 RMCS_CS dw 0 RMCS_SP dw 0 RMCS_SS dw 0 RModeCallStructure ENDS MyCallStruc RModeCallStructure <> globalD lpProc,0 if ROM externW gdtdsc endif public MS_DOS_Name_String MS_DOS_Name_String db "MS-DOS", 0 DataEnd INIT externFP IGlobalFree externFP IGlobalAlloc ifdef WOW externFP kSYSERRORBOX externFP VirtualAlloc endif sBegin CODE assumes cs,CODE assumes ds,nothing externNP genter extrn GrowHeapDib: FAR extrn LocalNotifyDib: FAR extrn LocalNotifyDefault: FAR extrn FreeHeapDib: FAR externNP gleave extrn IGlobalFix:FAR ;Far calls in this segment extrn GlobalHandleNorip:FAR extrn IGlobalFlags:FAR extrn IGlobalHandle: FAR extrn Free_Object2: FAR extrn mycsds:WORD ife ROM extrn gdtdsc:WORD endif ifdef WOW externD prevInt31proc endif sEnd CODE sBegin INITCODE assumes cs,CODE assumes ds,nothing ;=======================================================================; ; ; ; 386 PROTECTED MODE INITIALISATION ROUTINES ; ; ; ;=======================================================================; ife ROM ; this function is not used in ROM since DOSX switches to Pmode before ; jumping to kernel. this means the enhanced mode loader will have ; to do something similar... ;-----------------------------------------------------------------------; ; SwitchToPMODE ; ; ; ; Entry: ; ; In Real or Virtual Mode ; ; ES -> PSP ; ; ; ; Returns: ; ; In Protect Mode ; ; BX -> LDT selector ; ; SI -> Segment of start of available memory ; ; ES -> PSP ; ; ; ; Error Returns: ; ; Exits via DOS call 4Ch ; ; ; ; Registers Preserved: ; ; ; ; ; ; Registers Destroyed: ; ; ; ; Calls: ; ; ; ; History: ; ; ; ;-----------------------------------------------------------------------; assumes ds,DATA assumes es,nothing cProc SwitchToPMODE, cBegin nogen push cx push es ; Current PSP mov ax, 1687h int 2Fh ; Get PMODE switch entry or ax, ax ; Can we do it? jnz NoPMODE xor bh, bh ; Set CPU type now cmp cl, 3 ; At least a 386? jb NoPMODE mov bl,WF_CPU386 je short @F ; If 386 mov bl,WF_CPU486 ; No, assume 486 for now @@: mov WinFlags, bx ; Save away CPU type mov word ptr [lpProc][0], di mov word ptr [lpProc][2], es pop ax ; PSP add ax, 10h ; Skip the PSP mov es, ax ; Give this to the DOS extender add si, ax ; Start of memory available to us ; THIS IS IT FOLKS! xor ax, ax ; 16-bit app call [lpProc] ; Switch to PROTECTED mode jc NoPMODE ; No, still Real/Virtual mode mov ax, cs and al, 7 ; LDT, Ring 3 cmp al, 7 jne short BadDPMI ; Insist on Ring 3! mov bx, cs ; Allocate CS Alias DPMICALL 000Ah mov MyCSAlias, ax ; Save CS Alias in DS mov bx, ds ; Use alias to update code seg var mov ds, ax assumes ds, CODE mov MyCSDS, bx ; The DS selector mov ds, bx ReSetKernelDS push es push si mov ax, 168Ah ; See if we have MS-DOS extensions mov si, dataoffset MS_DOS_Name_String int 2Fh ; DS:SI -> MS-DOS string cmp al, 8Ah ; Have extensions? je short BadDPMI ; no extensions, screwed mov [lpProc][0], di ; Save CallBack address mov [lpProc][2], es mov ax, 0100h ; Get base of LDT call [lpProc] jc short NoLDTParty verw ax ; Writeable? jnz short NoLDTParty ; nope, don't bother with it yet mov es, MyCSAlias assumes es,CODE mov gdtdsc, ax assumes es,nothing NoLDTParty: pop si pop es push si ; Unlock all of our memory ifndef WOW ; For WOW its all pageable movzx ebx, si shl ebx, 4 ; Linear address of start of our memory movzx esi, es:[PDB_block_len] ; End of our memory shl esi, 4 sub esi, ebx ; Size of our block mov di, si shr esi, 10h mov cx, bx shr ebx, 10h mov ax, 0602h int 31h ; Mark region as pageable. endif pop bx mov ax, 2 ; Convert start of memory to selector int 31h mov si, ax xor bx, bx pop cx ret BadDPMI: ; ; Call real/virtual mode to whine ; xor cx, cx ; Nothing on stack to copy xor bh, bh ; Flags to DPMI mov ax, MyCSSeg mov MyCallStruc.RMCS_DS, ax ; Real mode DS will be parent PDB mov MyCallStruc.RMCS_ES, cx ; Real mode ES will be 0 mov MyCallStruc.RMCS_CS, ax ; Real mode CS mov MyCallStruc.RMCS_IP, codeoffset RModeCode ; Real mode IP smov es, ds mov di, dataOffset MyCallStruc ; ES:DI points to call structure mov ax, 0301h ; Call Real Mode Procedure int 31h jmps GoodBye RModeCode: mov dx, codeoffset szInadequate mov ah, 9 int 21h retf ;Inadequate: ; DB 'KRNL386: Inadequate DPMI Server',13,10,'$' externB NoPMODE: ; NOTE: stack trashed... ifdef WOW ;** Put Up a Dialog Box If we fail to Enter Protect Mode ;** Prepare the dialog box push cs ;In our DS push codeOFFSET szNoPMode ; -> unable to enter Prot Mode push ds externB push dataOffset syserr ;Caption push 0 ;No left button push SEB_CLOSE + SEB_DEFBUTTON ;Button 1 style push 0 ;No right button call kSYSERRORBOX ;Put up the system error message externNP ExitKernel jmp ExitKernel else ; Not WOW mov dx, codeoffset szNoPMode ; call complain ; DB 'KRNL386: Unable to enter Protected Mode',13,10,'$' ;complain: ; pop dx push cs pop ds ; DS:DX -> error message mov ah,9 ; Print error message int 21h endif; WOW GoodBye: mov ax, 4CFFh int 21h cEnd nogen endif ;-----------------------------------------------------------------------; ; LDT_Init ; ; ; ; Entry: ; ; DS -> CS ; ; ; ; Returns: ; ; ; ; Error Returns: ; ; ; ; Registers Preserved: ; ; AX,BX,CX,DX,DI,SI,DS,ES ; ; ; ; Registers Destroyed: ; ; ; ; Calls: ; ; ; ; History: ; ; ; ;-----------------------------------------------------------------------; cProc LDT_Init,, cBegin ReSetKernelDS cmp gdtdsc, 0 jz short SlowAllocation ; ; Scan LDT for free selectors and ; put on a linked list ; mov es, gdtdsc mov cx, 1 DPMICALL 0000h ; Get selector from win386 and al, NOT SEG_RING_MASK mov FirstFreeSel, ax ; Set up header mov si, ax mov word ptr es:[si], -1 mov word ptr es:[si].dsc_access, MY_SEL ; MINE! mov cx, es lsl ecx, ecx ; limit of LDT xor eax, eax steal_sels: mov di, si ; prev selector in list not_this_one: add si, DSC_LEN ; use add for flags jz short end_ldt cmp si, cx ja short end_ldt cmp dword ptr es:[si], eax jne not_this_one cmp dword ptr es:[si][4], eax jne not_this_one mov word ptr es:[di], si ; Link into list mov word ptr es:[si].dsc_access, MY_SEL ; MINE! inc CountFreeSel jmps steal_sels end_ldt: mov word ptr es:[di], -1 SlowAllocation: push es ; Get random selectors smov es, ds ReSetKernelDS es UnSetKernelDS ; Could get 3 selectors at once here, ; but get_sel is more efficient for just 1 mov cx, 1 ; Argument to get_sel call get_sel or si, SEG_RING mov kr1dsc, si call get_sel mov kr2dsc, si call get_sel mov blotdsc, si call get_sel or si, SEG_RING mov DemandLoadSel, si ; for demand loading segments smov ds, es pop es UnSetKernelDS es cEnd sEnd INITCODE sBegin CODE assumes cs,CODE assumes ds,nothing ;=======================================================================; ; ; ; SELECTOR ALLOCATION/DEALLOCATION ROUTINES ; ; ; ;=======================================================================; ;-----------------------------------------------------------------------; ; AllocSelector ; ; ; Entry: ; ; Returns: ; AX = 0 if out of selectors ; ; Registers Destroyed: ; ; History: ; Thu 08-Dec-1988 14:17:38 -by- David N. Weise [davidw] ; Wrote it! ;-----------------------------------------------------------------------; assumes ds,nothing assumes es,nothing ifdef WOW labelFP mov ax, 1 jmps AllocSelectorWorker labelFP xor ax, ax ; fall through cProc AllocSelectorWorker,, parmW selector localV OldDsc,DSC_LEN localW fDontSetDescriptor cBegin mov fDontSetDescriptor, ax else cProc AllocSelector,, parmW selector localV OldDsc,DSC_LEN cBegin endif mov cx, 1 lsl ecx, dword ptr selector jz short as_present call get_sel ; He passed in some junk, give him ifdef WOW ; just one selector... ; If we have a good selector, use DPMI to write it through to the ; system LDT before giving it to an application to use. jz short as_exit1 mov ax, [bp+4] ; Get caller CS. cmp ax, IGROUP ; Don't write thru if it's KRNL386 calling. je short as_exit cmp ax, _NRESTEXT je short as_exit cmp ax, _MISCTEXT je short as_exit ;Set shadow LDT entry to known state. push bx push ds mov ds, gdtdsc ; Get shadow LDT in DS UnSetKernelDS mov bx, si mov [bx].dsc_limit, 00h ; Set entry to: BASE = 0, LIMIT = 0, BYTES, mov [bx].dsc_lbase, 00h ; DPL = 3, PRESENT, DATA mov [bx].dsc_mbase, 00h mov [bx].dsc_hbase, 00h mov ax, DSC_DATA+DSC_PRESENT mov word ptr [bx].dsc_access, ax pop ds DPMICALL WOW_DPMIFUNC_0C ; Write shadow LDT entry thru to system LDT. pop bx jmps as_exit else jnz short as_exit ; just one selector... jmps as_exit1 endif as_present: Limit_To_Selectors ecx call get_sel jz short as_exit1 ifdef WOW test fDontSetDescriptor, 1 jnz as_exit endif smov es, ss lea di, OldDsc ; ES:DI points to descriptor mov bx, selector ; BX gets old selector push ds if ROM SetKernelDS endif mov ds, gdtdsc if ROM assumes ds,nothing endif push si ; Get Descriptor mov si, bx and si, not 7 MovsDsc lea di, [di-DSC_LEN] ; Restore DI pop si pop ds mov bx, si ; BX gets new selector or bl, SEG_RING call fill_in_selector_array ; and set new array to match as_exit: or si, SEG_RING as_exit1: mov ax,si cEnd ;-----------------------------------------------------------------------; ; AllocResSelArray - Allocate a resource Selector array (see resaux) ; ; Combination of AllocSelectorArray + SetResourceOwner; ; Entry: ; ; nSels = # selectors required ; ; parmW owner ; ; ; ; ; ; ; ; get_sel - get an array of selectors ; ; ; ; Entry: ; ; CX = # selectors required ; ; ; ; Returns: ; ; SI = First Selector ; ; DS = LDT ; ; ZF = 0 ; ; ; ; Error Returns: ; ; SI = 0 ; ; ZF = 1 ; ; ; ; Registers Preserved: ; ; DI,ES ; ; ; ; Registers Destroyed: ; ; ; ; Calls: ; ; ; ; History: ; ; mattfe March 30th 1993 - WOW Specific Routine, by combining the two ; ; routines I can reduce the number of DPMI calls by 40/1 for loading ; ; a typical app. ; ;-----------------------------------------------------------------------; ifdef WOW assumes ds, nothing assumes es, nothing cProc AllocResSelArray,, parmW nSels parmW owner cBegin mov cx, nSels call get_sel mov ax, si jz short ARSA_fail or si, SEG_RING mov bx, si mov dx, cx push ds mov ds, gdtdsc push bx and bl, not 7 ;; For the first selector mark it with the resource owner mov cx, owner mov ds:[bx].dsc_owner, cx mov word ptr ds:[bx].dsc_access, (DSC_DISCARDABLE SHL 8) + DSC_DATA mov cx,nSels mov ds:[bx].dsc_hbase, cl ; Save number of selectors here mov cx, DSC_DATA+DSC_PRESENT lea bx, [bx+DSC_LEN] dec dx jz ASRA_CallNT ARSA_fill_in_access: mov word ptr ds:[bx].dsc_access, cx lea bx, [bx+DSC_LEN] dec dx jnz ARSA_fill_in_access ASRA_CallNT: mov bx,si ; First Selector mov cx,nSels ; Count DPMICALL WOW_DPMIFUNC_0C SetKernelDS mov ds, pGlobalHeap UnSetKernelDS cCall AssociateSelector32, ; And save in selector table pop ax ; Return first sel pop ds ARSA_fail: cEnd endif ; WOW ;-----------------------------------------------------------------------; ; AllocSelectorArray - external entry for get_sel ; ; Entry: ; ; nSels = # selectors required ; ; ; ; get_sel - get an array of selectors ; ; ; ; Entry: ; ; CX = # selectors required ; ; ; ; Returns: ; ; SI = First Selector ; ; DS = LDT ; ; ZF = 0 ; ; ; ; Error Returns: ; ; SI = 0 ; ; ZF = 1 ; ; ; ; Registers Preserved: ; ; DI,ES ; ; ; ; Registers Destroyed: ; ; ; ; Calls: ; ; ; ; History: ; ; ; ;-----------------------------------------------------------------------; assumes ds, nothing assumes es, nothing cProc AllocSelectorArray,, parmW nSels cBegin mov cx, nSels call get_sel mov ax, si jz short asa_fail or si, SEG_RING mov bx, si mov dx, cx mov cx, DSC_DATA+DSC_PRESENT ifdef WOW ; LATER should use single op to update fill_in_access: ; complete LDT with one call. DPMICALL 0009h lea bx, [bx+DSC_LEN] dec dx jnz fill_in_access else push ds mov ds, gdtdsc push bx and bl, not 7 fill_in_access: mov word ptr ds:[bx].dsc_access, cx if 0 ;;ROM and KDEBUG call CheckROMSelector endif lea bx, [bx+DSC_LEN] dec dx jnz fill_in_access pop bx pop ds endif; WOW mov ax, si asa_fail: cEnd if KDEBUG cProc check_free_sel_list, cBegin pushf pusha push ds call SetKernelDSProc ; Must call direct in this file ReSetKernelDS mov cx, CountFreeSel cmp cx, 2 ; Only check list with more than 1 entry. jb cfl_ok inc cx ; Count dummy entry. mov si, FirstFreeSel ; Pointer to head of list mov ds, gdtdsc ; Get shadow LDT in DS UnSetKernelDS cfl_loop: mov ax, word ptr [si] ; Get next. cmp ax, 0FFFFH ; -1 is sentinal je short cfl_trashed mov di, si ; Save prev. for debugging. mov si, ax loop cfl_loop mov ax, word ptr [si] ; Get sentinal. cfl_done: cmp ax, 0FFFFH ; -1 is sentinal je short cfl_ok ; Must have sentinal and cfl_trashed: kerror 0, cfl_ok: pop ds popa popf cEnd endif cProc get_sel, localW MySel cBegin pusha gs_retry_get_sel: call SetKernelDSProc ; Must call direct in this file ReSetKernelDS mov si, FirstFreeSel ; Pointer to head of list mov ds, gdtdsc UnSetKernelDS mov dx, cx ; Sels wanted mov ax, word ptr [si] inc ax ; -1 teminated jz short gs_searchfailed if KDEBUG call check_free_sel_list endif cmp cx, 1 ; One selector only? jne short gs_selblock dec ax mov di, ax mov word ptr [di].dsc_access, DSC_USED ; Mark it used mov di, word ptr [di] ; Unlink it mov word ptr [si], di mov si, ax jmp got_my_sel gs_selblock: ; Following stolen from DOSX mov bx, si ; Start of list of free sels lea si, [si+DSC_LEN] ; Start search here! mov di, ds lsl di, di ; limit of LDT and di, NOT 7 gs_jail: mov ax, si ; Starting selector mov cx, dx ; number to check gs_sb0: cmp word ptr ds:[si].dsc_access, MY_SEL ; This one free? jnz short gs_sb1 ; nope, keep looking lea si, [si+DSC_LEN] cmp si, di ; Falling off the end? jae short gs_searchfailed loop gs_sb0 ; All we wanted? jmps gs_gotblock gs_sb1: lea si, [si+DSC_LEN] ; Restart scan after this selector cmp si, di jb short gs_jail jmps gs_searchfailed ; Got our block, now blast them out gs_gotblock: ; of the free list mov cx, dx ; # selectors push cx shl dx, 3 ; Length of our array of selectors add dx, ax ; First selector after our array mov si, [bx] ; Next selector in free list gs_blast: inc si jz short gs_blasted ; Gone thru whole list dec si cmp si, ax ; See if in range jb short gs_noblast cmp si, dx jb short gs_unlink gs_noblast: mov bx, si mov si, [si] ; Follow the link jmps gs_blast gs_unlink: ; This one is in range mov si, [si] ; Unlink it mov [bx], si loop gs_blast ; Stop search when unlinked them all gs_blasted: pop cx mov si, ax lea si, [si].dsc_access ; Now mark them used gs_markused: mov byte ptr [si], DSC_USED lea si, [si+DSC_LEN] cmp si, dx jb short gs_markused mov si, ax jmps got_my_sel gs_searchfailed: ; Failed from our list, try WIN386 mov cx, dx ;;;%out Take me out later ;;; mov ds, gdtdsc ;;; UnSetKernelDS gs_slow: ifdef WOW ;; Calling DPMI to do anything is very slow, so lets grab at minimum 256 ;; selectors at a time, that way we don't have to call again for a while call SetKernelDSProc ; Must call direct in this file ReSetKernelDS push cx test fbooting,1 ; Don't do optimization during boot ; since free_Sel will return them to ; DPMI. jnz gs_0100 add cx,256 ; get more than we need DPMICALL 0000h jc gs_0100 ; Failed, then just grab the required mov bx, ax ; number. gs_free_loop: cCall free_sel, ; Got the selectors, put them on lea bx, [bx+DSC_LEN] ; our free list the easy way... loop gs_free_loop pop cx jmp gs_retry_get_sel gs_0100: pop cx endif; WOW DPMICALL 0000h ; Call DPMI to get one and al, NOT SEG_RING_MASK mov si, ax or si, si ; Did we get it? jnz short got_dpmi_sel if KDEBUG push es pusha kerror 0, popa pop es jmp gs_exit else jmps gs_exit endif ; Try to avoid running out of selectors under Enhanced mode by keeping ; 256 selectors free. This will hopefully allow win386 to grow the ; LDT while there is still memory to do so. got_my_sel: SetKernelDS sub CountFreeSel, cx ifndef WOW ;; See above WOW code which grabs chunks of 256 selectors from DOSX ;; we don't need to do this. test byte ptr WinFlags, WF_ENHANCED ; Standard mode can't grow the jz got_either_sel ; LDT so don't bother cmp CountFreeSel, 256 jae got_either_sel lsl bx, gdtdsc ; LDT already full size? cmp bx, 0F000h ja got_either_sel push ax push cx mov cx, 256 DPMICALL 0000h jc gs_after_free mov bx, ax gs_free_it: cCall free_sel, ; Got the selectors, put them on lea bx, [bx+DSC_LEN] ; our free list the easy way... loop gs_free_it gs_after_free: pop cx pop ax endif; NOT WOW jmps got_either_sel got_dpmi_sel: SetKernelDS got_either_sel: cmp SelTableLen, 0 je short gs_exit ; Not set yet push eax .ERRNZ DSC_LEN-8 lea eax, [esi+ecx*DSC_LEN][-DSC_LEN] ; AX has last selector shr ax, 1 ; ignore high word... cmp ax, SelTableLen pop eax jb short gs_exit ; Can associate this selector if KDEBUG int 3 endif mov bx, si xor si, si or bl, SEG_RING as_free: DPMICALL 0001h ; Free selector ; Give to WIN386 since we can't use it lea bx, [bx+DSC_LEN] loop as_free gs_exit: mov ds, gdtdsc UnSetKernelDS mov MySel, si popa mov si, MySel or si, si ; Set ZF for caller cEnd ;-----------------------------------------------------------------------; ; alloc_disc_data_sel ; alloc_data_sel ; alloc_data_sel32 ; alloc_disc_CS_sel ; alloc_CS_sel ; alloc_NP_data_sel ; alloc_NP_CS_sel ; ; Set appropriate access rights flags then use ; alloc_sel to get a selector. ; ; Entry: ; Base address and Limit OR Owner ; ; Returns: ; Selector in AX ; ; Registers Destroyed: ; AX ; ; History: ; Fri 15-Jul-1988 21:05:19 -by- David N. Weise [davidw] ; ;-----------------------------------------------------------------------; assumes ds,nothing assumes es,nothing if ROM ; ; there is a bunch of selector allocating in the ROM initialization ; so have a couple functions for 16 bit limits... ; cProc far_alloc_data_sel16, parmD base parmW limit cBegin movzx eax, limit shl eax, 4 mov edx, base cCall alloc_data_sel, cEnd cProc alloc_data_sel16, parmD base parmW limit cBegin movzx eax, limit shl eax, 4 ;; this is is paragraphs... mov edx, base cCall alloc_data_sel, cEnd endif public alloc_data_sel32 alloc_data_sel32 label near cProc alloc_data_sel, ; parmD Address ; parmD Limit cBegin nogen mov ax,DSC_PRESENT+DSC_DATA jmps alloc_sel cEnd nogen ;-----------------------------------------------------------------------; ; alloc_sel ; ; ; ; Entry: ; ; AL = flags ; ; Returns: ; ; ; ; Error Returns: ; ; ; ; Registers Preserved: ; ; BX,CX,DX,DI,SI,DS,ES ; ; ; ; Registers Destroyed: ; ; ; ; Calls: ; ; ; ; History: ; ; ; ; Thu 07-Apr-1988 21:33:27 -by- David N. Weise [davidw] ; ; Added the GlobalNotify check. ; ; ; ; Sun Feb 01, 1987 07:48:39p -by- David N. Weise [davidw] ; ; Added this nifty comment block. ; ;-----------------------------------------------------------------------; cProc alloc_sel,, parmD Address parmD Limit localV DscBuf,DSC_LEN cBegin push ecx mov cx, 1 test al, DSC_PRESENT jz short as_oneonly mov ecx, Limit ; Calculate how many selectors required cmp ecx, 100000h ; More than 1Mb? jb short as_byte add ecx, 0FFFh ; Round to 4K pages and cx, not 0FFFh mov Limit, ecx shr Limit, 12 ; # 4K pages or ah, DSC_GRANULARITY ; 4K granularity! as_byte: dec Limit ; Came in as length, now limit add ecx, 0FFFFh shr ecx, 16 ; # selectors in array as_oneonly: call get_sel jz short a_s_exit ; No selectors left mov bx, si ; Selector in bx for DPMI or bl, SEL_LDT lea di, DscBuf smov es, ss ; es:di points to descriptor buffer test al, DSC_PRESENT jnz short set_everything push ax if ROM SetKernelDS mov ds, gdtdsc assumes ds,nothing else mov ds, gdtdsc endif and bl, not 7 pop word ptr [bx].dsc_access mov ax, word ptr Limit mov [bx].dsc_limit, ax mov [bx].dsc_hbase, cl ; Number of selectors here ifdef WOW smov es, ds ; es:di -> descriptor mov di, bx or bl, SEG_RING ; bx selector # DPMICALL 000Ch ; Set descriptor endif; WOW jmps as_done set_everything: and ah, not 0Fh ; Zero limit 19:16 or ah, byte ptr Limit+2 ; Fill in limit 19:16 mov word ptr DscBuf.dsc_access, ax mov ax, Limit.lo mov DscBuf.dsc_limit, ax mov ax, Address.lo mov DscBuf.dsc_lbase, ax mov ax, Address.hi mov DscBuf.dsc_mbase, al mov DscBuf.dsc_hbase, ah call fill_in_selector_array as_done: or si, SEG_RING a_s_exit: mov ax, si pop ecx cEnd ;-----------------------------------------------------------------------; ; free_sel ; ; FreeSelector ; ; ; ; Entry: ; ; ; ; Returns: ; ; ; ; Error Returns: ; ; ; ; Registers Preserved: ; ; AX,BX,CX,DX,DI,SI,DS,ES ; ; ; ; Registers Destroyed: ; ; ; ; Calls: ; ; ; ; History: ; ; ; ;-----------------------------------------------------------------------; assumes ds,nothing assumes es,nothing cProc IFreeSelector, parmW selector cBegin xor ax, ax mov es, ax cCall FreeSelArray, cEnd assumes ds, nothing assumes es, nothing ifdef WOW ; save cx too. cProc free_sel,, else cProc free_sel,, endif parmW selector cBegin pushf ; !!! for the nonce mov bx,selector ; must be careful in gcompact ; to ignore error return call SetKernelDSProc ; Must call direct in this file ReSetKernelDS if ROM ; don't free ROM selectors... cmp bx, sel1stAvail jb sel_freed endif cmp gdtdsc, 0 je short give_to_win386 sel_check bx mov si, bx shr si, 1 cmp si, SelTableLen if 0 mov si, SelTableLen shl si, 1 cmp bx, si endif jae short give_to_win386 mov si, FirstFreeSel inc CountFreeSel mov ds, gdtdsc UnSetKernelDS ifdef WOW mov cx, word ptr [bx+4] endif ; Link into list mov ax, [si] ; ax := head.next mov [si], bx ; head.next := new mov [bx], ax ; new.next := ax mov word ptr [bx][2], 0 mov dword ptr [bx][4], MY_SEL SHL 8 ; Make it free ifdef WOW cmp cx, MY_SEL jz sel_freed or bl, SEG_RING ; Ensure Table bit correct mov cx, 1 DPMICALL WOW_DPMIFUNC_0C endif jmps sel_freed give_to_win386: or bl, SEG_RING ; Ensure Table bit correct DPMICALL 0001H sel_freed: popf cEnd ;-----------------------------------------------------------------------; ; FreeSelArray ; ; ; ; Entry: ; ; ; ; Returns: ; ; ; ; Error Returns: ; ; ; ; Registers Preserved: ; ; AX,BX,CX,DX,DI,SI,DS,ES ; ; ; ; Registers Destroyed: ; ; ; ; Calls: ; ; ; ; History: ; ; ; ;-----------------------------------------------------------------------; assumes ds,nothing assumes es,nothing cProc FreeSelArray,, parmW selector cBegin push ecx mov cx, 1 ; In case lar, lsl fail, one sel to free mov bx, selector Handle_To_Sel bl ifdef WOW if KDEBUG push ds SetKernelDS cmp DemandLoadSel, 0 ; Skip the test if we're freeing DemandLoadSel UnSetKernelDS pop ds je short fsa_no_test push bx push ds mov ds, gdtdsc and bl, not 7 mov ch, [bx].dsc_access pop ds pop bx lar ax, bx and ah, 0feh ;ignore access bit and ch, 0feh ;ignore access bit cmp ah, ch je short LDTs_match kerror 0, LDTs_match: xor ch, ch fsa_no_test: endif endif lar ax, bx jnz short just_free_it ; I'm completely confused... test ah, DSC_CODEDATA ; Code or data? jz short just_free_it ; No, assume only one selector test ah, DSC_PRESENT ; Present? jnz short use_limit ; yes, calculate # sels from limit ifdef WOW ; MarkSelNotPresent Saves Number of selectors in the dsc_hbase entry to get ; it back directly from our copy of the LDT. push bx push ds mov ds, gdtdsc and bl, not 7 xor cx,cx mov cl,[bx].dsc_hbase ; Get Saved # selectors pop ds pop bx else push dx ; DPMI call 6 returns CX:DX DPMICALL 0006h ; Get physical address shr cx, 8 ; number of selectors pop dx endif; WOW jmps just_free_it use_limit: lsl ecx, ebx jnz short just_free_it ; Not present Limit_To_Selectors ecx just_free_it: if KDEBUG cmp cl,ch jnz short skip_zero_inc kerror 0, inc cl skip_zero_inc: endif just_free_it2: cCall free_sel, ; (preserves cx) lea bx, [bx+DSC_LEN] loop just_free_it2 ; Any left to free pop ecx cEnd ;-----------------------------------------------------------------------; ; GrowSelArray ; ; ; ; Entry: ; ; ; ; Returns: ; ; ; ; Error Returns: ; ; AX = 0 ; ; ZF = 1 ; ; ; ; Registers Preserved: ; ; AX,BX,CX,DX,DI,SI,DS,ES ; ; ; ; Registers Destroyed: ; ; ; ; Calls: ; ; ; ; History: ; ; ; ;-----------------------------------------------------------------------; assumes ds,nothing assumes es,nothing cProc GrowSelArray,, localV DscBuf,DSC_LEN cBegin push ecx mov di, ds:[esi].pga_handle mov bx, di Handle_To_Sel di lsl eax, edi Limit_To_Selectors eax if KDEBUG cmp al, ds:[esi].pga_selcount je short gsa_count_ok int 3 int 3 gsa_count_ok: endif mov ecx, edx ; New size add ecx, 0FFFFh shr ecx, 16 ; new # selectors cmp ax, cx ; Same # of selectors required? je short gsa_done ; yes, just return! push si push es push ds push di ; Argument to FreeSelArray cmp cx, 255 ; Max array is 255. jae short gsa_nosels call get_sel ; get a new selector array jz short gsa_nosels push bx mov bx, di ; DI had original selector push ds if ROM SetKernelDS mov es,gdtdsc mov ds,gdtdsc assumes ds,nothing else mov ds,gdtdsc mov es,gdtdsc endif push si mov di,si and di, not 7 mov si,bx and si, not 7 MovsDsc pop si pop ds ifdef WOW push cx push bx mov cx, 1 mov bx, si or bx, SEG_RING_MASK DPMICALL WOW_DPMIFUNC_0C pop bx pop cx endif mov di, si ; New selector in DI pop bx pop si pop ds cCall AssociateSelector32, pop es pop si mov ax, bx and ax, SEG_RING_MASK ; Ring bits or ax, di ; New handle mov ds:[esi].pga_handle, ax mov ds:[esi].pga_selcount, cl cCall AssociateSelector32, jmps gsa_done gsa_nosels: pop di pop ds pop es pop si xor ax, ax ; Indicate failure jmps gsa_ret gsa_done: mov ax, ds:[esi].pga_handle or ax, ax ; Success gsa_ret: pop ecx cEnd ;=======================================================================; ; ; ; SELECTOR ALIAS ROUTINES ; ; ; ;=======================================================================; ;-----------------------------------------------------------------------; ; PrestoChangoSel ; ; ; Entry: ; ; Returns: ; ; Registers Destroyed: ; ; History: ; Thu 08-Dec-1988 14:17:38 -by- David N. Weise [davidw] ; Wrote it! ;-----------------------------------------------------------------------; assumes ds,nothing assumes es,nothing cProc IPrestoChangoSelector,, parmW sourcesel parmW destsel localV DscBuf,DSC_LEN cBegin ifdef WOW smov es, ss lea di, DscBuf mov bx, sourcesel DPMICALL 000Bh ; LATER change this to a single xor DscBuf.dsc_access, DSC_CODE_BIT ; DPMI call, read from gdtdsc mov bx, destsel DPMICALL 000Ch mov ax, bx else push bx push ds if ROM SetKernelDS mov es, gdtdsc mov ds, gdtdsc assumes ds, nothing else mov ds, gdtdsc mov es, gdtdsc endif mov si, sourcesel and si, not 7 mov di, destsel and di, not 7 MovsDsc lea bx,[di-DSC_LEN] xor ds:[bx].dsc_access,DSC_CODE_BIT ; Toggle CODE/DATA pop ds or bl, SEG_RING mov ax, bx pop bx endif; WOW smov es,0 cEnd ;-----------------------------------------------------------------------; ; AllocAlias ; ; AllocCStoDSAlias ; ; AllocDStoCSAlias ; ; All these routines return an alias selector for the ; ; given selector. ; ; ; ; Entry: ; ; ; ; Returns: ; ; AX is alias selector ; ; DX is original selector (compatibility thing) ; ; ; ; Error Returns: ; ; ; ; Registers Preserved: ; ; BX,CX,DI,SI,DS ; ; ; ; Registers Destroyed: ; ; ES destroyed ; ; ; ; Calls: ; ; ; ; History: ; ; ; ;-----------------------------------------------------------------------; assumes ds,nothing assumes es,nothing labelFP ;** AllocDStoCSAlias has an interesting hack. A fix was made to ;** not allow apps to GlobalAlloc fixed memory. This was done ;** for performance reasons. The only reason we can ascertain ;** for an app needing fixed GlobalAlloc'ed memory is in the case ;** of alias selectors. We assume that all apps needing alias ;** selectors will use this function to make the alias. So, if ;** we see a DStoCS alias being made, we make sure the DS is fixed. push bp mov bp, sp ;Create the stack frame push WORD PTR [bp + 6] ;Get handle/selector IF KDEBUG call GlobalHandleNorip ;Make sure it's really a handle ELSE call IGlobalHandle ;Make sure it's really a handle ENDIF test ax, 1 ;Fixed blocks have low bit set jnz SHORT ADCA_Already_Fixed ;It's already a fixed block! ;** If the block is not fixed, it may be locked so we must check this. push ax ;Save returned selector push ax ;Use as parameter call IGlobalFlags ;Returns lock count if any or al, al ;Non-zero lock count? pop ax ;Get selector back jnz SHORT ADCA_Already_Fixed ;Yes, don't mess with it ;** Fix the memory. Note that we're only doing this for the ;** apps that are calling this on non-fixed or -locked memory. ;** This will cause them to rip on the GlobalFree call to this ;** memory, but at least it won't move on them! push ax ;Fix it call IGlobalFix ADCA_Already_Fixed: pop bp ;Clear our stack frame ;** Flag which type of alias to make and jump to common routine mov dl, 1 jmps aka labelFP xor dl, dl cProc aka,, parmW sourceSel localV DscBuf,DSC_LEN localB flag ; 0 for data, !0 for code cBegin mov flag, dl mov cx, 1 call get_sel mov ax, si ; in case it failed jz short aka_nope or si, SEG_RING ifdef WOW ; LATER Single DPMI call push si ; save Target Selector smov es,ss lea di,DscBuf mov bx,sourceSel DPMICALL 000Bh ; Read the Selector into DscBuf and es:[di].dsc_access,NOT DSC_CODE_BIT ; Toggle CODE/DATA cmp flag, 0 jz @F or es:[di].dsc_access,DSC_CODE_BIT @@: pop bx ; restore Target Selector DPMICALL 0000Ch else if ROM SetKernelDS mov es, gdtdsc mov ds, gdtdsc assumes ds, nothing else mov ds, gdtdsc mov es, gdtdsc endif mov bx, si mov di, si and di, not 7 mov si, sourceSel and si, not 7 MovsDsc and es:[di][-DSC_LEN].dsc_access,NOT DSC_CODE_BIT ; Toggle CODE/DATA cmp flag, 0 jz @F or es:[di][-DSC_LEN].dsc_access,DSC_CODE_BIT @@: endif; WOW mov ax, bx smov es,0 aka_nope: mov dx,sourceSel cEnd cProc AllocAlias,, parmW selector cBegin ifdef WOW push bx ; Whitewater tool ObjDraw needs this too endif mov cx, 1 call get_sel jz short aca_nope or si, SEG_RING cCall IPrestoChangoSelector, aca_nope: ; WhiteWater Resource Toolkit (shipped with Borland's Turbo ; Pascal) depends on dx being the data selector which was true ; in 3.0 but in 3.1 validation layer destroys it. mov dx,selector ifdef WOW pop bx endif cEnd ;=======================================================================; ; ; ; SELECTOR MANPULATION ROUTINES ; ; ; ;=======================================================================; ;-----------------------------------------------------------------------; ; fill_in_selector_array ; ; ; ; Entry: ; ; AX = Limit for object ; ; DH = Discard bit for descriptors ; ; DL = Access bits ; ; BX:DI = 32 bit base address of object ; ; SI = index into LDT ; ; Returns: ; ; ; ; Error Returns: ; ; ; ; Registers Preserved: ; ; SI, DI, DS, ES ; ; ; ; Registers Destroyed: ; ; AX,BX,CX,DX ; ; ; ; Calls: ; ; ; ; History: ; ; ; ;-----------------------------------------------------------------------; cProc fill_in_selector_array, cBegin nogen push ds mov ds, gdtdsc push bx push cx mov dh, es:[di].dsc_hlimit ; For granularity next_sel: ;; DPMICALL 000Ch ; Set this descriptor push bx ; Set Descriptor and bl, not 7 mov ax, es:[di] ; This looks slow but it isn't... mov ds:[bx], ax mov ax, es:[di][2] mov ds:[bx][2], ax mov ax, es:[di][4] mov ds:[bx][4], ax mov ax, es:[di][6] mov ds:[bx][6], ax pop bx lea bx, [bx+DSC_LEN] ; On to next selector add es:[di].dsc_mbase, 1 ; Add 64kb to address adc es:[di].dsc_hbase, 0 test dh, DSC_GRANULARITY ; Page granular? jz short byte_granular sub es:[di].dsc_limit, 16 ; 64K is 16 4K pages sbb es:[di].dsc_hlimit, 0 ; Carry into hlimit loop next_sel jmps fisa_ret byte_granular: dec es:[di].dsc_hlimit ; subtract 64kb from limit loop next_sel fisa_ret: pop cx pop bx DPMICALL WOW_DPMIFUNC_0C pop ds ret cEnd nogen ;-----------------------------------------------------------------------; ; GetSelectorBase ; get_physical_address ; ; ; Entry: ; ; Returns: ; DX:AX 32 bit physical address ; Registers Destroyed: ; ; History: ; Sat 09-Jul-1988 16:40:59 -by- David N. Weise [davidw] ; ;-----------------------------------------------------------------------; assumes ds,nothing assumes es,nothing cProc GetSelectorBase, parmW selector cBegin cCall get_physical_address, cEnd cProc get_physical_address, parmW selector cBegin push bx push cx mov bx, selector push ds ; Get Segment Base Address if ROM SetKernelDS mov ds, gdtdsc assumes ds, nothing else mov ds, gdtdsc endif and bl, not 7 mov ax, ds:[bx].dsc_lbase mov dl, ds:[bx].dsc_mbase mov dh, ds:[bx].dsc_hbase pop ds pop cx pop bx cEnd ;-----------------------------------------------------------------------; ; get_selector_length16 ; ; ; Entry: ; ; Returns: ; AX 16 bit segment length ; Registers Destroyed: ; ; History: ; Sat 09-Jul-1988 16:40:59 -by- David N. Weise [davidw] ; ;-----------------------------------------------------------------------; assumes ds,nothing assumes es,nothing cProc get_selector_length16, parmW selector cBegin mov ax, -1 lsl ax, selector inc ax ; length is one bigger! cEnd ;-----------------------------------------------------------------------; ; set_physical_address ; ; ; Entry: ; DX:AX 32 bit physical address ; Returns: ; ; Registers Destroyed: ; ; History: ; Sat 09-Jul-1988 16:40:59 -by- David N. Weise [davidw] ; ;-----------------------------------------------------------------------; assumes ds,nothing assumes es,nothing cProc far_set_physical_address, parmW selector cBegin cCall set_physical_address, cEnd cProc set_physical_address,, parmW selector cBegin push ecx mov bx, selector CheckLDT bl lsl ecx, ebx if KDEBUG jz short spa_ok int 3 spa_ok: endif Limit_To_Selectors ecx mov di, cx mov cx, dx ; CX:DX has new address mov dx, ax push ds push bx if ROM SetKernelDS mov ds, gdtdsc assumes ds, nothing else ifdef WOW set_bases: DPMICALL 0007h ; Set selector base else mov ds, gdtdsc set_bases: and bl, not 7 mov ds:[bx].dsc_lbase, dx mov ds:[bx].dsc_mbase, cl mov ds:[bx].dsc_hbase, ch endif; WOW lea bx, [bx+DSC_LEN] ; On to next selector inc cx ; Add 64k to base dec di jnz set_bases pop bx pop ds endif; ROM mov ax, dx ; Restore AX and DX mov dx, cx pop ecx cEnd ;-----------------------------------------------------------------------; ; set_selector_address32 ; ; ; Entry: ; ; Returns: ; ; Registers Destroyed: ; ; History: ; Sat 09-Jul-1988 16:40:59 -by- David N. Weise [davidw] ; ;-----------------------------------------------------------------------; assumes ds,nothing assumes es,nothing cProc set_selector_address32,, parmW selector parmD addr cBegin mov dx, addr.sel mov ax, addr.off cCall set_physical_address, cEnd ;-----------------------------------------------------------------------; ; set_sel_limit ; ; ; Entry: ; CX:BX = length of segment ; Returns: ; ; Registers Destroyed: ; CX ; ; History: ; Fri 15-Jul-1988 19:41:44 -by- David N. Weise [davidw] ; ;-----------------------------------------------------------------------; assumes ds,nothing assumes es,nothing cProc set_sel_limit,, parmW selector localV DscBuf,DSC_LEN cBegin push ebx push ecx push bx ; Get existing descriptor smov es, ss lea di, DscBuf mov bx, selector push ds ; Get Descriptor if ROM SetKernelDS mov ds, gdtdsc assumes ds,nothing else mov ds, gdtdsc endif push si mov si, bx and si, not 7 MovsDsc lea di, [di-DSC_LEN] ; Restore DI pop si pop ds pop bx mov dx, word ptr [DscBuf.dsc_access] and dh, 0F0h ; Zap hlimit bits test dl, DSC_PRESENT jz short ssl_set_limit1 ; Not present, just one to set and dh, NOT DSC_GRANULARITY ; Byte granularity shl ecx, 16 mov cx, bx ; DWORD length mov ebx, ecx cmp ecx, 100000h ; More than 1Mb? jb short ssl_byte add ecx, 0FFFh ; Round to 4k pages and cx, not 0FFFh mov ebx, ecx shr ebx, 12 ; # 4k pages or dh, DSC_GRANULARITY ; Set 4k granularity ssl_byte: add ecx, 0FFFFh shr ecx, 16 ; # selectors in array cmp cx, 1 je short ssl_set_limit1 dec ebx ; length to limit mov ax, bx ; low 16 bits of limit shr ebx, 16 or dh, bl ; Bits 19:16 of limit mov word ptr DscBuf.dsc_access, dx mov DscBuf.dsc_limit, ax mov bx, Selector call fill_in_selector_array jmps ssl_done ssl_set_limit1: ; Fast out for one only dec bx ; Came in as length mov DscBuf.dsc_limit, bx ; and limit mov word ptr DscBuf.dsc_access, dx ; Access, Discard and hlimit mov bx, Selector DPMICALL 000Ch ssl_done: smov ss,ss ; It may be SS we're changing pop ecx pop ebx cEnd ;-----------------------------------------------------------------------; ; set_selector_limit32 ; ; ; Entry: ; ; Returns: ; ; Registers Destroyed: ; ; History: ; Fri 15-Jul-1988 19:41:44 -by- David N. Weise [davidw] ; ;-----------------------------------------------------------------------; assumes ds,nothing assumes es,nothing cProc set_selector_limit32,, parmW selector parmD sel_len cBegin mov cx, sel_len.hi mov bx, sel_len.lo cCall set_sel_limit, cEnd ;-----------------------------------------------------------------------; ; mark_sel_NP ; ; ; Entry: ; ; Returns: ; ; Registers Destroyed: ; BX ; ; History: ; Fri 15-Jul-1988 21:37:22 -by- David N. Weise [davidw] ; ;-----------------------------------------------------------------------; assumes ds,nothing assumes es,nothing cProc mark_sel_NP,, parmW selector parmW owner localV DscBuf,DSC_LEN cBegin push ecx mov bx, selector Handle_To_Sel bl lsl ecx, ebx ; How many selectors do we have now? Limit_To_Selectors ecx push ax push es push di push ds if ROM SetKernelDS mov ds, gdtdsc assumes ds, nothing else mov ds, gdtdsc endif push bx and bl, not 7 mov [bx].dsc_hbase, cl ; Save # selectors mov [bx].dsc_hlimit, DSC_DISCARDABLE and [bx].dsc_access, NOT DSC_PRESENT mov cx, owner mov [bx].dsc_owner, cx ; Set owner in descriptor ifdef WOW ; ; Now the copy of the LDT has the correct info set VIA DPMI the real NT ; LDT Entry smov es,ds mov di,bx ; es:di->selector or bx, SEG_RING ; BX = selector DPMICALL 000Ch endif; WOW pop bx pop ds SetKernelDS mov ds, pGlobalHeap UnSetKernelDS cCall AssociateSelector32, ; Save owner in selector table pop di pop es pop ax pop ecx cEnd ;-----------------------------------------------------------------------; ; mark_sel_PRESENT ; ; ; Entry: ; ; Returns: ; ; Registers Destroyed: ; ; History: ; Fri 15-Jul-1988 21:37:22 -by- David N. Weise [davidw] ; ;-----------------------------------------------------------------------; assumes ds,nothing assumes es,nothing cProc mark_sel_PRESENT,, parmD arena_ptr parmW selector localV DscBuf,DSC_LEN cBegin push eax push ebx push ecx smov es, ss lea di, DscBuf mov bx, selector DPMICALL 000Bh ; Get existing descriptor mov ax, word ptr DscBuf.dsc_access ; Access and hlimit or al, DSC_PRESENT ; Mark it present and ah, NOT DSC_GRANULARITY ; Assume byte granular mov esi, arena_ptr CheckDS mov ecx, ds:[esi].pga_size mov ebx, ecx cmp ecx, 100000h ; New size more than 1Mb? jb short msp_byte add ebx, 0FFFh ; Round to 4k pages and bx, not 0FFFh shr ebx, 12 ; # 4k pages or ah, DSC_GRANULARITY ; Set 4k granularity msp_byte: dec ebx mov DscBuf.dsc_limit, bx ; Fill in new limit fields shr ebx, 16 and bl, 0Fh and ah, NOT 0Fh or ah, bl mov word ptr DscBuf.dsc_access, ax ; Fill in new hlimit and access dec ecx Limit_To_Selectors ecx ; New number of selectors mov ds:[esi].pga_selcount, cl mov bl, DscBuf.dsc_hbase ; Old number of selectors sub bl, cl je short go_ahead ; Same number, just fill in array jb short get_big ; here to get small xor bh, bh xchg bx, cx shl bx, 3 ; Offset of first selector .errnz DSC_LEN - 8 add bx, selector ; First selector to free @@: cCall free_sel, lea bx, [bx+DSC_LEN] loop @B jmps go_ahead ; And fill in remaining selectors get_big: mov ax, word ptr DscBuf.dsc_access ; Access bits in ax mov ebx, ds:[esi].pga_address ; Get base address mov ecx, ds:[esi].pga_size cCall alloc_sel, ; Access bits in ax mov si, ax or ax, ax ; did we get a set? jz short return_new_handle or si, SEG_RING ; Set ring bits like old selector test selector, IS_SELECTOR jnz short @F StoH si HtoS selector @@: cCall AssociateSelector32, cCall FreeSelArray, ; Zap old handle jmps return_new_handle go_ahead: mov ebx, ds:[esi].pga_address ; Fill in selector array with mov DscBuf.dsc_lbase, bx ; new base and limit shr ebx, 16 mov DscBuf.dsc_mbase, bl mov DscBuf.dsc_hbase, bh mov bx, selector movzx cx, ds:[esi].pga_selcount call fill_in_selector_array mov si, selector ; return old selector in SI return_new_handle: pop ecx pop ebx pop eax cEnd ;-----------------------------------------------------------------------; ; cmp_sel_address ; ; Compares the physical addresses corresponding to two selectors ; ; Entry: ; ; Returns: ; ; Registers Destroyed: ; ; History: ; Sat 09-Jul-1988 19:10:14 -by- David N. Weise [davidw] ; ;-----------------------------------------------------------------------; assumes ds,nothing assumes es,nothing cProc cmp_sel_address, parmW sel1 parmW sel2 cBegin push ax push ebx push edx cCall get_physical_address, mov bx, dx shl ebx, 16 mov bx, ax ; First address in EBX cCall get_physical_address, shl edx, 16 mov dx, ax ; Second address in EDX cmp ebx, edx pop edx pop ebx pop ax ;;; mov ds,gdtdsc ;;; mov si,sel1 ;;; mov di,sel2 ;;; sel_check si ;;; sel_check di ;;; mov al,[si].dsc_hbase ;;; cmp al,[di].dsc_hbase ;;; jne short csa_done ;;; mov al,[si].dsc_mbase ;;; cmp al,[di].dsc_mbase ;;; jne short csa_done ;;; mov ax,[si].dsc_lbase ;;; cmp ax,[di].dsc_lbase ;;;csa_done: cEnd ;-----------------------------------------------------------------------; ; pdref ; ; ; ; Dereferences the given global handle, i.e. gives back abs. address. ; ; ; ; Arguments: ; ; DX = selector ; ; DS:DI = BURGERMASTER ; ; ; ; Returns: ; ; ESI = address of arena header ; ; AX = address of client data ; ; CH = lock count or 0 for fixed objects ; ; CL = flags ; ; DX = handle, 0 for fixed objects ; ; ; ; Error Returns: ; ; ZF = 1 if invalid or discarded ; ; AX = 0 ; ; BX = owner of discarded object ; ; SI = handle of discarded object ; ; ; ; Registers Preserved: ; ; ; ; Registers Destroyed: ; ; ; ; Calls: ; ; ; ; History: ; ; ; ;-----------------------------------------------------------------------; assumes ds,nothing assumes es,nothing cProc pdref, cBegin nogen mov si, dx sel_check si or si, si ; Null handle? mov ax, si jz short pd_exit ; yes, return 0 lar eax, edx jnz short pd_totally_bogus shr eax, 8 ; We should beef up the check for a valid discarded sel. xor cx,cx test ah, DSC_DISCARDABLE jz short pd_not_discardable or cl, GA_DISCARDABLE ; Discardable, is it code? test al, DSC_CODE_BIT jz short pd_not_code or cl,GA_DISCCODE pd_not_code: pd_not_discardable: test al, DSC_PRESENT jnz short pd_not_discarded ; object discarded or cl,HE_DISCARDED ifdef WOW ; On WOW we don't copy the owner to the real LDT since it is slow to call ; the NT Kernel, so we read our copy of it directly. ; see set_discarded_sel_owner mattfe mar 23 93 move ax,es ; save es mov bx,dx mov es,cs:gdtdsc and bl, not 7 mov bx,es:[bx].dsc_owner mov es,ax ; restore else lsl bx, dx ; get the owner endif or si, SEG_RING-1 ; Handles are RING 2 xor ax,ax jmps pd_exit pd_not_discarded: cCall get_arena_pointer32, mov esi, eax mov ax, dx or esi, esi ; Unknown selector jz short pd_maybe_alias mov dx, ds:[esi].pga_handle cmp dx, ax ; Quick check - handle in header je short pd_match ; matches what we were given? test al, IS_SELECTOR ; NOW, we MUST have been given jz short pd_totally_bogus ; a selector address. push ax StoH al ; Turn into handle cmp dx, ax pop ax jne short pd_nomatch pd_match: or cl, ds:[esi].pga_flags and cl, NOT HE_DISCARDED ; same as GA_NOTIFY!! mov ax, dx ; Get address in AX test dl, GA_FIXED ; DX contains handle jnz short pd_fixed ; Does handle need derefencing? mov ch, ds:[esi].pga_count HtoS al ; Dereference moveable handle jmps pd_exit pd_totally_bogus: xor ax,ax pd_maybe_alias: ife ROM if KDEBUG or dx,dx jnz short dref_invalid endif endif pd_nomatch: ; Handle did not match... xor dx, dx ;;; mov dx, ax ; Must be an alias... pd_fixed: ;;; xor si, si ;;; xor dx, dx pd_exit: or ax,ax ret if KDEBUG dref_invalid: push ax kerror ERR_GMEMHANDLE,,0,dx pop ax jmps pd_nomatch endif cEnd nogen cProc Far_pdref, cBegin nogen call pdref ret cEnd nogen ;-----------------------------------------------------------------------; ; get_rover_2 ; ; ; ; Entry: ; ; ES Selector to get rover for ; ; Returns: ; ; ES (kr2dsc) is rover DATA and PRESENT ; ; Error Returns: ; ; ; ; Registers Preserved: ; ; AX,BX,CX,DX,DI,SI,DS ; ; ; ; Registers Destroyed: ; ; ; ; Calls: ; ; ; ; History: ; ; ; ;-----------------------------------------------------------------------; assumes ds,nothing assumes es,nothing cProc get_rover_2,, localV DscBuf,DSC_LEN cBegin push ax push bx mov bx, es ; Selector to get rover for push ds SetKernelDS ds mov di, kr2dsc mov es, gdtdsc mov ds, gdtdsc UnSetKernelDS ds push si mov si, bx and si, not 7 and di, not 7 MovsDsc lea bx, [di-DSC_LEN] mov es:[bx].dsc_access, DSC_PRESENT+DSC_DATA or bl, SEG_RING pop si ifdef WOW push cx mov cx, 1 DPMICALL WOW_DPMIFUNC_0C pop cx endif; WOW pop ds mov es, bx ; Return with ES containing rover pop bx pop ax cEnd ;-----------------------------------------------------------------------; ; get_rover_232 ; ; ; ; Entry: ; ; ds:esi ; ; Returns: ; ; ES:0 ; ; Error Returns: ; ; ; ; Registers Preserved: ; ; AX,BX,CX,DX,DI,SI,DS ; ; ; ; Registers Destroyed: ; ; ; ; Calls: ; ; ; ; History: ; ; ; ;-----------------------------------------------------------------------; ifndef WOW_x86 assumes ds,nothing assumes es,nothing cProc get_rover_232,, localV DscBuf,DSC_LEN cBegin push eax push bx SetKernelDS es mov bx, kr2dsc or bl, SEG_RING smov es, ss UnSetKernelDS es lea di, DscBuf ; ES:DI -> descriptor mov eax, ds:[esi].pga_address mov [DscBuf].dsc_lbase, ax ; Fill in base address shr eax, 16 mov [DscBuf].dsc_mbase, al mov [DscBuf].dsc_hbase, ah mov [DscBuf].dsc_limit, 1000h ; Real big limit mov [DscBuf].dsc_hlimit, DSC_GRANULARITY mov [DscBuf].dsc_access,DSC_PRESENT+DSC_DATA DPMICALL 000Ch ; Set descriptor mov es, bx pop bx pop eax cEnd endif; WOW cProc far_get_temp_sel, cBegin cCall get_temp_sel cEnd cProc get_temp_sel,, localV DscBuf,DSC_LEN cBegin mov cx, 1 DPMICALL 0000h ; Get us a selector push bx mov si, ax ; New selector mov bx, es ; Old selector ifdef WOW ; LATER Make single dpmicall smov es, ss lea di, DscBuf DPMICALL 000Bh ; Get existing descriptor mov DscBuf.dsc_access,DSC_PRESENT+DSC_DATA mov DscBuf.dsc_limit,0ffffh or DscBuf.dsc_hlimit, 0Fh ; Max length mov bx, si or bl, SEG_RING DPMICALL 000Ch ; Set new descriptor else push ds if ROM SetKernelDS mov es, gdtdsc mov ds, gdtdsc UnsetKernelDS else mov ds, gdtdsc mov es, gdtdsc endif mov di, si and di, not 7 mov si, bx and si, not 7 MovsDsc lea bx, [di-DSC_LEN] mov [bx].dsc_access,DSC_PRESENT+DSC_DATA mov [bx].dsc_limit,0ffffh or [bx].dsc_hlimit, 0Fh ; Max length or bl, SEG_RING pop ds endif; WOW mov es, bx pop bx cEnd cProc far_free_temp_sel, parmW selector cBegin cCall free_sel, cEnd ;-----------------------------------------------------------------------; ; get_blotto ; ; ; Entry: ; EAX = arena header ; ; Returns: ; BX = Selector points to pga_address (size pga_arena) ; Registers Destroyed: ; ; History: ; Sun 31-Jul-1988 16:20:53 -by- David N. Weise [davidw] ; ;-----------------------------------------------------------------------; assumes ds,nothing assumes es,nothing ifndef WOW_x86 ;; On WOW_x86 we try to avoid setting selectors since it is slow, we use selector ;; 23h to write to anywhere in VDM memory. cProc get_blotto,, localV DscBuf,DSC_LEN cBegin push es push bx lea di, DscBuf SetKernelDS es mov bx, blotdsc smov es, ss UnSetKernelDS es or bl, SEG_RING push eax mov eax, ds:[eax].pga_address mov [DscBuf].dsc_lbase,ax shr eax, 16 mov [DscBuf].dsc_mbase,al mov [DscBuf].dsc_hbase,ah ; Convert pga_size to limit in page granularity pop eax mov eax, ds:[eax].pga_size ; Get Size in Bytes add eax, 4096-1 ; Round up to 4k multiple shr eax, 3*4 mov [DscBuf].dsc_limit,ax shr eax,16 or al, DSC_GRANULARITY mov [DscBuf].dsc_hlimit, al mov [DscBuf].dsc_access,DSC_PRESENT+DSC_DATA DPMICALL 000Ch ; Set up the descriptor mov ax, bx pop bx pop es cEnd endif; ;-----------------------------------------------------------------------; ; LongPtrAdd ; ; Performs segment arithmetic on a long pointer and a DWORD offset ; The resulting pointer is normalized to a paragraph boundary. ; The offset cannot be greater than 16 megabytes (current Enh Mode ; limit on size of an object). ; ; Entry: ; ; Returns: ; DX:AX new segment:offset ; ; Error returns: ; DX:AX = 0 ; ; Registers Destroyed: ; BX,CX ; ; History: ; Mon 19-Dec-1988 18:37:23 -by- David N. Weise [davidw] ; Wrote it! ;-----------------------------------------------------------------------; assumes ds,nothing assumes es,nothing ifdef WOW LPTRADDWOW_SETBASE equ 01h ;cProc LongPtrAddWOW,, ; parmD long_ptr ; parmD delta ; parmW RefSelector ; parmW flBaseSetting ; ; effectively pops RefSelector and flBaseSetting into dx and ax. ; and jumps to longptrAddWorker. ; ; RefSelector is used only if the descriptor needs to be set. ; labelFP pop ax pop dx ; far return address mov bx,sp xchg ax, ss:[bx] ; replace the 'dword' with the return address xchg dx, ss:[bx+2] jmps LongPtrAddWorker ; ax = flags; dx = reference selector labelFP mov ax, LPTRADDWOW_SETBASE xor dx, dx ; fall through cProc LongPtrAddWorker,, parmD long_ptr parmD delta localV DscBuf,DSC_LEN localW flBaseSetting localW RefSelector cBegin mov flBaseSetting, ax ; save in localvariables mov RefSelector, dx or dx, dx ; if RefSelector is nonzero jz @F ; use it for querying descriptor info. xchg dx, word ptr long_ptr[2] ; and store the selector to be set in mov RefSelector, dx ; the localvariable @@: else cProc LongPtrAdd,, parmD long_ptr parmD delta localV DscBuf,DSC_LEN cBegin endif mov bx,word ptr long_ptr[2] lea di, DscBuf smov es, ss DPMICALL 000Bh ; Pick up old descriptor mov ax,word ptr long_ptr[0] ; get the pointer into SI:AX and ax,0FFF0h mov si, DscBuf.dsc_lbase ; DX:SI gets old base mov dl, DscBuf.dsc_mbase mov dh, DscBuf.dsc_hbase add si, ax ; Add in old pointer offset adc dx, 0 mov cx, word ptr delta[2] ; add the segment and MSW test cx, 0FF00h ; bigger than 16Meg? ifdef WOW jz @F test flBaseSetting, LPTRADDWOW_SETBASE jnz lptr_mustset jmp short lpa_too_big @@: else jnz short lpa_too_big endif add si, word ptr delta[0] ; add the offset and LSW adc dx, cx ifdef WOW lptr_mustset: endif mov cx, 1 ; Calculate # selectors now in array lsl ecx, dword ptr long_ptr[2] jnz short trash Limit_to_Selectors ecx trash: ifdef WOW test flBaseSetting, LPTRADDWOW_SETBASE jz lptr_dontset cmp RefSelector, 0 jz @F mov bx, RefSelector ; get the actual selector to be set mov word ptr long_ptr[2], bx @@: endif mov DscBuf.dsc_lbase, si ; Put new base back in descriptor mov DscBuf.dsc_mbase, dl mov DscBuf.dsc_hbase, dh call fill_in_selector_array ifdef WOW lptr_dontset: test word ptr delta[2], 0ff00h jz @F mov cx, word ptr delta[2] jmps lpa_too_big @@: endif mov dx,word ptr long_ptr[2] mov ax,word ptr long_ptr[0] and ax, 0Fh jnc short lpa_exit lpa_too_big: xor ax,ax xor dx,dx lpa_exit: smov es,0 cEnd ;-----------------------------------------------------------------------; ; SetSelectorBase ; ; Sets the base and limit of the given selector. ; ; Entry: ; parmW selector ; parmD selbase ; ; Returns: ; AX = selector ; ; Error Returns: ; AX = 0 ; ; History: ; Tue 23-May-1989 21:10:29 -by- David N. Weise [davidw] ; Wrote it! ;-----------------------------------------------------------------------; assumes ds,nothing assumes es,nothing cProc SetSelectorBase, parmW selector parmD selbase cBegin push bx push cx push dx mov cx, selbase.hi mov dx, selbase.lo mov bx, selector ifdef WOW DPMICALL 0007h ; Set Segment Base Address else push ds if ROM SetKernelDS mov ds, gdtdsc UnsetKernelDS else mov ds, gdtdsc endif push bx and bl, not 7 mov ds:[bx].dsc_lbase, dx mov ds:[bx].dsc_mbase, cl mov ds:[bx].dsc_hbase, ch pop bx pop ds endif; WOW pop dx pop cx pop bx mov ax,selector cEnd ;-----------------------------------------------------------------------; ; GetSelectorLimit ; ; Sets the limit of the given selector. ; ; Entry: ; parmW selector ; ; Returns: ; DX:AX = limit of selector ; ; Registers Destroyed: ; ; History: ; Tue 23-May-1989 21:10:29 -by- David N. Weise [davidw] ; Wrote it! ;-----------------------------------------------------------------------; assumes ds,nothing assumes es,nothing cProc GetSelectorLimit, parmW selector cBegin xor eax, eax ; In case lsl fails lsl eax, dword ptr selector mov edx, eax shr edx, 16 cEnd ;-----------------------------------------------------------------------; ; SetSelectorLimit ; ; Sets the limit of the given selector. ; ; Entry: ; parmW selector ; parmD sellimit ; ; Returns: ; AX = 0 success ; ; Registers Destroyed: ; ; History: ; Tue 23-May-1989 21:10:29 -by- David N. Weise [davidw] ; Wrote it! ;-----------------------------------------------------------------------; assumes ds,nothing assumes es,nothing cProc SetSelectorLimit, parmW selector parmD sellimit localV DscBuf,DSC_LEN cBegin ifdef WOW mov bx, selector mov dx, word ptr sellimit[0] mov cx, word ptr sellimit[2] DPMICALL 0008h else push es push di mov bx,selector push ds if ROM SetKernelDS mov ds, gdtdsc UnsetKernelDS else mov ds, gdtdsc endif and bl, not 7 mov ax,sellimit.lo mov [bx].dsc_limit,ax mov ax,sellimit.hi and al,0Fh ; AND out flags and [bx].dsc_hlimit,0F0h ; AND out hi limit or [bx].dsc_hlimit,al pop ds pop di pop es endif; WOW xor ax,ax ; for now always return success cEnd ;-----------------------------------------------------------------------; ; SelectorAccessRights ; ; Sets the access and other bytes of the given selector. ; ; Entry: ; parmW selector ; parmW getsetflag ; parmD selrights ; ; Returns: ; AX = 0 success ; ; Registers Destroyed: ; ; History: ; Tue 23-May-1989 21:10:29 -by- David N. Weise [davidw] ; Wrote it! ;-----------------------------------------------------------------------; assumes ds,nothing assumes es,nothing cProc SelectorAccessRights, parmW selector parmW getsetflag parmW selrights cBegin mov bx, selector lar eax, ebx ; Get current access rights shr eax, 8 ; in AX cmp getsetflag,0 jnz short sar_set and ax, 0D01Eh ; Hide bits they can't play with jmps sar_exit sar_set: mov cx, selrights and cx, 0D01Eh ; Zap bits they can't set and and ax, NOT 0D01Eh ; get them from existing access rights or cx, ax DPMICALL 0009h ; Set new access rights xor ax,ax ; for now always return success sar_exit: cEnd cProc SetKernelCSDwordProc,, parmw addr parmw hiword parmw loword cBegin SetKernelDS mov ds, MyCSAlias UnSetKernelDS mov bx, addr mov ax, loword mov [bx], ax mov ax, hiword mov [bx+2], ax cEnd cProc GetKernelDataSeg, cBegin nogen mov ax, cs:MyCSDS ret cEnd nogen cProc SetKernelDSProc, cBegin nogen mov ds, cs:MyCSDS ret cEnd nogen cProc SetKernelESProc, cBegin nogen mov es, cs:MyCSDS ret cEnd nogen assumes ds, nothing assumes es, nothing cProc PreallocArena, cBegin nogen push ds push eax cCall alloc_arena_header, call SetKernelDSProc ReSetKernelDS mov temp_arena, eax or eax, eax ; Set flags for caller pop eax pop ds UnSetKernelDS ret cEnd nogen assumes ds, nothing assumes es, nothing cProc alloc_arena_header,, parmD Address localV DscBuf,DSC_LEN cBegin SetKernelDS es push ebx xor eax, eax cmp temp_arena, eax ; Have one waiting? je short aah_look ; no, get one xchg temp_arena, eax ; Use the waiting selector jmp aah_found aah_look: cmp FreeArenaCount, 0 jnz aah_ok ; Out of arenas, try to get push ecx push si push di xor bx, bx mov cx, ARENA_INCR_BYTES DPMICALL 0501h jc short aah_no_memory if 0 push si push di mov ax, 0600h ; Page lock it mov di, ARENA_INCR_BYTES xor si, si int 31h pop di pop si jnc short aah_got_memory give_it_back: DPMICALL 0502h ; No good, give it back else jmp short aah_got_memory endif aah_no_memory: pop di pop si pop ecx xor eax, eax ; We are REALLY out of arenas! jmp aah_exit aah_got_memory: shl ebx, 16 mov bx, cx ; Address of our new arenas cCall get_arena_pointer32,; Arena of burgermaster sub ebx, [eax].pga_address ; Above present arenas? lea ecx, [ebx+ARENA_INCR_BYTES+0FFFh] shr ecx, 12 ; #pages selector must cover dec ecx ; limit with page granularity cmp ecx, HighestArena jbe short aah_limitOK mov HighestArena, ecx push es push bx mov bx, ds lea di, DscBuf smov es, ss DPMICALL 000Bh ; Get DS descriptor mov [DscBuf].dsc_limit, cx ; Set the new limit in the descriptor shr ecx, 16 and cl, 0fh ; hlimit bits and [DscBuf].dsc_hlimit, not 0fh; Zap old ones or cl, DSC_GRANULARITY ; Granularity bit or [DscBuf].dsc_hlimit, cl DPMICALL 000Ch ; Set new limit pop bx pop es aah_limitOK: mov cx, ARENA_INCR_BYTES shr cx, 5 ; # arenas to add aah_loop: cCall free_arena_header, ; Free up all our new arenas add ebx, size GlobalArena32 loop aah_loop pop di pop si pop ecx aah_ok: mov eax, FreeArenaList if KDEBUG inc eax jnz short aah_ook int 3 int 3 aah_ook: dec eax endif mov ebx, ds:[eax.pga_next] mov FreeArenaList, ebx dec FreeArenaCount aah_found: mov ebx, Address mov ds:[eax.pga_address], ebx mov dword ptr ds:[eax.pga_count], 0 aah_exit: pop ebx cEnd assumes ds, nothing assumes es, nothing cProc free_arena_header,, parmD arena cBegin push eax push ebx SetKernelDS es CheckDS mov ebx, arena mov eax, FreeArenaList mov ds:[ebx.pga_next], eax mov FreeArenaList, ebx inc FreeArenaCount pop ebx pop eax cEnd assumes ds, nothing assumes es, nothing cProc FarAssociateSelector32, parmW Selector parmD ArenaPtr cBegin cCall AssociateSelector32, cEnd cProc AssociateSelector32,, parmW Selector parmD ArenaPtr cBegin CheckDS SetKernelDS es push eax push ebx movzx ebx, Selector and bl, NOT SEG_RING_MASK shr bx, 1 if KDEBUG cmp bx, SelTableLen jb short as_ok INT3_NEVER INT3_NEVER as_ok: endif add ebx, SelTableStart mov eax, ArenaPtr mov ds:[ebx], eax pop ebx pop eax cEnd assumes ds, nothing assumes es, nothing cProc far_get_arena_pointer32, parmW Selector cBegin cCall get_arena_pointer32, cEnd cProc get_arena_pointer32, parmW Selector cBegin CheckDS push es SetKernelDS es push ebx movzx ebx, Selector and bl, not SEG_RING_MASK shr bx, 1 cmp bx, SelTableLen jb short gap_ok xor eax, eax ; Bogus, return null jmps gap_exit gap_ok: add ebx, SelTableStart mov eax, ds:[ebx] if ROM ; hack for ROM-owned selectors. these do not have arenas ; but the owner is stored in the low word. ack ack ack!! ; cmp eax, 0FFFF0000h jb short @F xor eax, eax @@: endif if KDEBUG or eax, eax jz short gap_exit ; Bogus, return null push si mov si, ds:[eax].pga_handle sel_check si or si, si jz short gap32_match ; Boot time... sub ebx, SelTableStart shl bx, 1 cmp bx, si je short gap32_match xor eax, eax ; put back in 5 feb 90, alias avoided ;;; xor eax, eax ; Removed - may be an alias! gap32_match: pop si endif gap_exit: pop ebx pop es cEnd assumes ds, nothing assumes es, nothing cProc FarGetOwner,, parmW Selector cBegin cCall GetOwner, cEnd cProc GetOwner,, parmW Selector cBegin GENTER32 ;;;push eax ;; why??? ax gets trashed anyway. cCall get_arena_pointer32, if ROM or eax, eax jnz short @F cCall GetROMOwner, jmp short go_solong @@: endif or eax, eax jz go_solong mov bx, ds:[eax].pga_owner ;;;pop eax mov ax, bx go_solong: GLEAVE32 cEnd assumes ds, nothing assumes es, nothing cProc FarSetOwner, parmW Selector parmW owner cBegin cCall SetOwner, cEnd assumes ds, nothing assumes es, nothing cProc SetOwner,, parmW Selector parmW owner cBegin GENTER32 ; Assume ds not set! push eax cCall get_arena_pointer32, push owner pop ds:[eax].pga_owner pop eax GLEAVE32 cEnd assumes ds, nothing assumes es, nothing cProc PageLockLinear,, parmD address parmD len cBegin mov bx, word ptr address+2 mov cx, word ptr address mov si, word ptr len+2 mov di, word ptr len DPMICALL 0600h ; Let it return with carry flag from int 31h cEnd assumes ds, nothing assumes es, nothing cProc FarValidatePointer, parmD lpointer cBegin cCall ValidatePointer, cEnd cProc ValidatePointer, parmD lpointer cBegin lar ax, lpointer.sel jnz short bad_p ; Really bad selector test ah, DSC_PRESENT ; Must be present jz short bad_p lsl eax, dword ptr lpointer.sel movzx ecx, lpointer.off cmp eax, ecx ; Is the offset valid? jae short good_p bad_p: xor ax, ax jmps vp_done good_p: mov ax, 1 vp_done: cEnd assumes ds, nothing assumes es, nothing OneParaBytes dw 10h cProc SelToSeg,, parmW selector cBegin cCall get_physical_address, div cs:OneParaBytes ; Smaller than rotates cEnd cProc SegToSelector,, parmW smegma cBegin mov bx, smegma DPMICALL 0002h ; Make win386 do it cEnd ;-----------------------------------------------------------------------; ; set_discarded_sel_owner ; ; Sets the owner of a selector that points to a discarded object, ; which lives in the limit field. ; ; Entry: ; BX = selector to mark ; ES = owner ; ; Returns: ; nothing ; ; Registers Destroyed: ; BX ; ; History: ; Sun 03-Dec-1989 21:02:24 -by- David N. Weise [davidw] ; Wrote it! ;-----------------------------------------------------------------------; assumes ds,nothing assumes es,nothing cProc set_discarded_sel_owner, localV DscBuf,DSC_LEN cBegin push cx push di mov cx, es if KDEBUG ifdef WOW lea di, DscBuf smov es, ss DPMICALL 000Bh push cx xor cx,cx ; For debug build write 0 to LDT mov DscBuf.dsc_owner, cx DPMICALL 000Ch pop cx endif endif push ds if ROM SetKernelDS mov ds, gdtdsc UnsetKernelDS else mov ds, gdtdsc endif push bx and bl, not 7 mov [bx].dsc_owner, cx pop bx pop ds push ds SetKernelDS mov ds, pGlobalHeap UnSetKernelDS cCall AssociateSelector32, ; And save in selector table pop ds mov es, cx pop di pop cx cEnd ;-----------------------------------------------------------------------; ; SetResourceOwner ; ; Sets the owner of a selector that points to a not present resource ; ; Entry: ; ; Returns: ; nothing ; ; Registers Destroyed: ; ; History: ;-----------------------------------------------------------------------; assumes ds,nothing assumes es,nothing cProc SetResourceOwner,, parmW selector parmW owner parmW selCount localV DscBuf,DSC_LEN cBegin mov bx, selector mov cx, owner ifdef WOW smov es, ss lea di, DscBuf DPMICALL 000Bh ; Get current descriptor mov DscBuf.dsc_owner, cx mov word ptr DscBuf.dsc_access, (DSC_DISCARDABLE SHL 8) + DSC_DATA mov cx,selCount mov DscBuf.dsc_hbase, cl ; Save number of selectors here DPMICALL 000Ch ; Set it with new owner else push ds if ROM SetKernelDS mov ds, gdtdsc UnsetKernelDS else mov ds, gdtdsc endif push bx and bl, not 7 mov [bx].dsc_owner, cx mov word ptr [bx].dsc_access, (DSC_DISCARDABLE SHL 8) + DSC_DATA mov cx, selCount mov [bx].dsc_hbase, cl ; Save number of selectors here pop bx pop ds endif; WOW SetKernelDS mov ds, pGlobalHeap UnSetKernelDS cCall AssociateSelector32, ; And save in selector table cEnd cProc GetAccessWord, parmW selector cBegin lar eax, dword ptr selector ; 386 or better, can use LAR shr eax, 8 cEnd ;-----------------------------------------------------------------------; ; DPMIProc ; ; Called NEAR by the DPMICALL macro - ; this is better than intercepting int 31h ; ; By sheer fluke, all intercepts return with ; Carry clear ie no error. ; ;-----------------------------------------------------------------------; cProc DPMIProc, cBegin nogen if 0 cmp ax,WOW_DPMIFUNC_0C jne @f INT3_TEST push ds SetKernelDS ds cmp high0c,cx ja popit mov high0c,cx popit: pop ds @@: endif ifdef WOW cmp ax,501h jne normal push eax push edx shl ebx,16 ; ebx = bx:cx mov bx,cx xor eax,eax mov ecx,PAGE_READWRITE mov edx,MEM_COMMIT_RESERVE cCall VirtualAlloc, mov bx,dx ; DPMI returns BX:CX - linear Address mov cx,ax mov si,dx ; FAKE dpmi "handle" - linear Address mov di,ax or ax,dx ; NULL is Error pop edx pop eax clc jnz @f ; OK Jump stc ; else set error @@: ret normal: endif ; WOW or ah, ah jz @F ife KDEBUG ifdef WOW_x86 ; ; If it is the wow set selector call we will just set the selector ; directly using int 2a (only for the single selector case) ; cmp ax,WOW_DPMIFUNC_0C jne CallServer cmp cx,1 jne CallServer call WowSetSelector jc CallServer ret endif endif CallServer: ifndef WOW int 31h ; Nope, call DPMI server ret else test word ptr [prevInt31Proc + 2],0FFFFh jz dp30 dp20: pushf call [prevInt31Proc] ret endif @@: ifdef WOW cmp gdtdsc, 0 ; Can we party? jz CallServer ; Nope endif push ds mov ds, gdtdsc ifdef WOW or al, al jnz @F mov ax, WOW_DPMIFUNC_00 pop ds jmp CallServer @@: endif cmp al, 0Bh jne short @F push si ; Get Descriptor - used very often! mov si, bx and si, not 7 MovsDsc lea di, [di-DSC_LEN] ; Restore DI pop si pop ds ret ifndef WOW @@: cmp al, 0Ch jne @F push bx ; Set Descriptor and bl, not 7 mov ax, es:[di] ; This looks slow but it isn't... mov ds:[bx], ax mov ax, es:[di][2] mov ds:[bx][2], ax mov ax, es:[di][4] mov ds:[bx][4], ax mov ax, es:[di][6] mov ds:[bx][6], ax if 0 ;;ROM and KDEBUG call CheckROMSelector endif pop bx pop ds ret @@: cmp al, 07h ; Set Segment Base Address jne @F push bx and bl, not 7 mov ds:[bx].dsc_lbase, dx mov ds:[bx].dsc_mbase, cl mov ds:[bx].dsc_hbase, ch pop bx pop ds ret endif @@: cmp al, 06h ; Get Segment Base Address jne @F push bx and bl, not 7 mov dx, ds:[bx].dsc_lbase mov cl, ds:[bx].dsc_mbase mov ch, ds:[bx].dsc_hbase pop bx pop ds ret ifndef WOW @@: cmp al, 09h ; Set Descriptor Access Rights jne @F push bx and bl, not 7 mov word ptr ds:[bx].dsc_access, cx if 0 ;;ROM and KDEBUG call CheckROMSelector endif pop bx pop ds ret endif @@: pop ds jmp CallServer ifdef WOW dp30: int 31h ret endif cEnd nogen ife KDEBUG ifdef WOW_x86 ;-----------------------------------------------------------------------; ; WowSetSelector ; ; Entry ; BX contains selector # ; ; Exit ; CY clear for success ; ; ;-----------------------------------------------------------------------; cProc WowSetSelector, cBegin nogen push ds push es push eax push ecx push edx push ebx push ebp SetKernelDS ds ; ; Check to see if we can do this ; mov edx, FlatAddressArray or edx, edx stc jz wss50 ; ; put the base of the selector in the flat address array ; mov es,gdtdsc and bx, NOT SEG_RING mov ax, FLAT_SEL mov ds, ax mov ah, es:[bx].dsc_hbase mov al, es:[bx].dsc_mbase shl eax,16 mov ax, es:[bx].dsc_lbase movzx ecx,bx shr ecx,1 ; dword index from selector index add ecx, edx ; point to proper spot in array mov [ecx], eax ; ; Form the limit of the selector ; movzx dx, byte ptr es:[bx].dsc_hlimit and dx,0fh ; remove gran etc. shl edx, 16 mov dx, es:[bx].dsc_limit ; ; Adjust for granularity ; test es:[bx].dsc_hlimit, DSC_GRANULARITY jz wss10 shl edx,12 or edx,0fffh ; ; Verify that the base/limit combination is allowed ; duplicate of code in dpmi32/i386/dpmi386.c ; wss10: cmp edx,07ffeffffh ja wss30 mov ecx,eax add ecx,edx cmp ecx,07ffeffffh jb wss40 ; ; Limit is too high, so adjust it downward ; wss30: mov edx,07ffeffffh sub edx,eax sub edx,0fffh ; ; fix for granularity ; test es:[bx].dsc_hlimit, DSC_GRANULARITY jz wss35 shr edx,12 ; ; store the new limit in the descriptor table ; wss35: mov es:[bx].dsc_limit,dx shr edx,16 movzx ax,es:[bx].dsc_hlimit and ax,0f0h ; mask for gran etc and dx,00fh ; mask for limit bits or dx,ax ; put back gran etc mov es:[bx].dsc_hlimit,dl ; ; Call the system to set the selector ; ; int 2a special case for wow: ; ; eax = 0xf0f0f0f1 ; ebp = 0xf0f0f0f1 ; ebx = selector ; ecx = first dword of the descriptor (LODWORD) ; edx = second dword of the descriptor (HIDWORD) wss40: mov eax, 0f0f0f0f1h mov ebp, 0f0f0f0f1h mov ecx, dword ptr es:[bx] mov edx, dword ptr es:[bx+4] movzx ebx,bx or bl, 3 int 02ah wss50: pop ebp pop ebx pop edx pop ecx pop eax pop es pop ds ret cEnd nogen endif ; WOW_x86 endif if ROM ;----------------------------------------------------------------------------- ; ; Functions for ROM Windows ; ; ;----------------------------------------------------------------------------- ; ; HocusROMBase ; ;----------------------------------------------------------------------------- assumes ds,nothing assumes es,nothing assumes fs,nothing assumes gs,nothing cProc HocusROMBase, parmW selector cBegin push bx push cx push dx push ds SetKernelDS mov bx, selector DPMICALL 0006h mov ax, cx shl eax, 16 mov ax, dx sub eax, lmaHiROM jb not_in_hi_rom cmp eax, cbHiROM jae not_in_hi_rom add eax, linHiROM mov dx, ax shr eax, 16 mov cx, ax DPMICALL 0007h not_in_hi_rom: mov ax, bx pop ds UnsetKernelDS pop dx pop cx pop bx cEnd ;----------------------------------------------------------------------------- ; ; ChangeROMHandle ; ;----------------------------------------------------------------------------- assumes ds,nothing assumes es,nothing assumes fs,nothing assumes gs,nothing cProc ChangeROMHandle, , parmW hold parmW hnew localV dscbuf, DSC_LEN cBegin SetKernelDS mov ds, ArenaSel UnsetKernelDS mov bx, hold cCall get_arena_pointer32, or eax, eax jz short crh_bummer_dude push eax mov si, bx and si, SEG_RING_MASK or si, hnew smov es, ss lea di, dscbuf DPMICALL 000Bh xchg bx, si DPMICALL 000Ch cCall AssociateSelector32, pop eax test dscbuf.dsc_access, DSC_PRESENT jz short @F mov ds:[eax].pga_handle, bx @@: cCall AssociateSelector32, cCall FreeSelArray, mov ax, bx crh_bummer_dude: cEnd ;----------------------------------------------------------------------------- ; ; CloneROMSelector ; ;----------------------------------------------------------------------------- assumes ds,nothing assumes es,nothing assumes fs,nothing assumes gs,nothing cProc CloneROMSelector, , parmW selROM parmW selClone cBegin SetKernelDS mov di, selROM mov es, selROMTOC assumes es, nothing and di, NOT SEG_RING_MASK sub di, es:[FirstROMSel] mov es, selROMLDT mov bx, selClone DPMICALL 000Ch cCall HocusROMBase, mov ds, ArenaSel cCall AssociateSelector32, mov ax, bx cEnd ;----------------------------------------------------------------------------- ; ; Get/SetROMOwner ; ;----------------------------------------------------------------------------- assumes ds,nothing assumes es,nothing assumes fs,nothing assumes gs,nothing cProc SetROMOwner, , parmW selector parmW owner cBegin GENTER32 cCall AssociateSelector32, GLEAVE32 cEnd cProc FarSetROMOwner, parmW selector parmW owner cBegin cCall SetROMOwner, cEnd cProc GetROMOwner, , parmW selector cBegin UnsetKernelDS SetKernelDS es mov ds, ArenaSel movzx ebx, selector and bl, not SEG_RING_MASK shr bx, 1 cmp bx, SelTableLen jae short gro_nope add ebx, SelTableStart mov eax, ds:[ebx] cmp eax, 0FFFF0000h jae short gro_ok gro_nope: xor eax, eax gro_ok: cEnd ;----------------------------------------------------------------------------- ; ; IsROMObject ; ;----------------------------------------------------------------------------- assumes ds,nothing assumes es,nothing assumes fs,nothing assumes gs,nothing cProc IsROMObject, , parmW selector localV DscBuf, DSC_LEN cBegin if KDEBUG mov ax, selector sel_check ax endif mov bx, selector smov es, ss lea di, DscBuf DPMICALL 000Bh SetKernelDS ES mov ah, DscBuf.dsc_hbase mov al, DscBuf.dsc_mbase shl eax, 16 mov ax, DscBuf.dsc_lbase sub eax, linHiROM jc short iro_not_rom sub eax, cbHiROM jnc short iro_not_rom mov al, 1 jmps iro_exit iro_not_rom: xor eax, eax iro_exit: cEnd cProc FarIsROMObject, parmW selector cBegin cCall IsROMObject, cEnd endif ifdef WOW ;----------------------------------------------------------------------------- ; Grab the selector 0x47 so that we dont need to special case the biosdata ; selector (0x40) while converting seg:off address to flat 32bit address ; ; This, however should not be part of Krnl286 heap. ; ; - Nanduri Ramakrishna ;----------------------------------------------------------------------------- cProc AllocSelector_0x47,, cBegin ; alloc the specific selector mov bx, 047h DPMICALL 0dh jc as47_exit ; initialize the LDT and bx, not SEG_RING mov ds, gdtdsc mov [bx].dsc_limit, 00h ; = 1 byte mov [bx].dsc_lbase, 0400h mov [bx].dsc_mbase, 00h mov [bx].dsc_hbase, 00h mov ax, DSC_DATA+DSC_PRESENT and ah, not 0Fh ; Zero limit 19:16 mov word ptr [bx].dsc_access, ax ; set the LDT mov cx,1 mov bx, 047h DPMICALL WOW_DPMIFUNC_0C as47_exit: cEnd endif sEnd CODE sBegin NRESCODE assumes CS,NRESCODE assumes DS,NOTHING assumes ES,NOTHING ; All the code below is to support DIB.DRV and WING. cProc get_sel_flags, parmW selector cBegin SetKernelDSNRes mov ds,pGlobalHeap cCall far_get_arena_pointer32, or eax,eax jz gsf5 movzx ax, byte ptr ds:[eax].pga_flags gsf5: xor dx,dx cEnd cProc set_sel_for_dib, parmW selector parmW flags parmW addressLo parmW addressHi parmW csel cBegin SetKernelDSNRes push ecx push ebx push fs push es ; if the selector has a value of -1, it means we either need to allocate ; or deallocate an array of selectors. If we are allocating, csel will have ; a count of 64k selectors. If csel is 0, we need to deallocate the selector ; array pointed to by address. cmp selector,-1 jne ssfSetDIB ; see if we are actually deleting the selector array cmp csel,0 jne ssfAllocSel ; free selector array at addressHi cCall IFreeSelector, mov ax,1 mov dx,0 jmp ssf5 ssfAllocSel: ; we need to have the selector array created cCall AllocSelectorArray, mov selector,ax xor dx,dx cmp ax,0 je ssf5 ; we must set the limits in the selectors. Each selector ; must have a limit in bytes for the remainder of the buffer. If there are ; 3 selectors, the first will be 0x0002ffff, the second 0x0001ffff, the ; third 0x0000ffff. mov cx,csel mov bx,selector ssfSetLimit: sub cx,1 ; 1 less each time cCall SetSelectorLimit, add bx,DSC_LEN ; advance to the next selector cmp cx,0 ; see if we have any more selector to set jne ssfSetLimit mov dx,addressHi mov ax,addressLo push selector call far_set_physical_address mov ax,0 ; return the first selector mov dx,selector jmp ssf5 ssfSetDIB: push ds mov ds,pGlobalHeap cCall far_get_arena_pointer32, or eax,eax jz ssf5 pop fs push eax ; save arena ptr cCall GrowHeapDib, or eax,eax jnz ssf0 pop eax xor eax,eax jmp ssf5 ssf0: pop esi ; ds:esi is arena ptr push eax ; save the new arena xor edi,edi ; ds:edi is global heap info cCall Free_Object2 mov dx,addressHi mov ax,addressLo cCall far_set_physical_address, pop eax push eax cCall FarAssociateSelector32, ; now see that the GAH_PHANTOM flag is set in the arena pop edx or ds:[edx].pga_flags, GAH_PHANTOM ; Now check if we are operating on a local heap. If so we change the ; LocalNotifyDefault to LocalNotifyDib. push es push selector pop es xor edi,edi mov di,word ptr es:[pLocalHeap] or di,di jz ssf4 ; Its not a local heap cmp edi,ds:[edx].pga_size jae ssf4 ; Its not a local heap cmp word ptr es:[di].li_sig,LOCALHEAP_SIG ; es:li_sig == LH jne ssf4 if KDEBUG cmp word ptr es:[di].li_notify,codeOFFSET LocalNotifyDefault jne ssf2 cmp word ptr es:[di].li_notify+2,codeBase je ssf3 ssf2: krDebugOut , "Set_Sel_For_Dib: App has hooked LocalNotifyDefault" ssf3: endif mov word ptr es:[di].li_notify,codeOFFSET LocalNotifyDib mov word ptr es:[di].li_notify+2,codeBase ssf4: pop es mov eax,1 ssf5: pop es pop fs pop ebx pop ecx cEnd cProc RestoreDib, parmW selector parmW flags parmD address localw hNewDib localw cSel localD DibSize localD NewArena localD OldArena cBegin SetKernelDSNRes push ecx push ebx push fs push es ;; Allocate a new global block xor eax, eax ; In case lsl fails lsl eax, dword ptr selector or eax,eax jz rd_fail inc eax mov DibSize,eax cCall IGlobalAlloc, or ax,ax jz rd_fail mov hNewDib,ax push ds pop fs mov ds,pGlobalHeap cCall far_get_arena_pointer32, mov OldArena,eax or eax,eax jz rd2 movzx ax, word ptr [eax].pga_selcount mov cSel,ax cCall far_get_arena_pointer32, or eax,eax jnz rd5 rd2: cCall IGlobalFree, jmp rd_fail rd5: mov NewArena,eax cld push ds mov ecx,DibSize mov ax, hNewDib or ax, 1 mov es, ax mov ds, selector xor esi, esi xor edi, edi mov eax,ecx shr ecx,2 ; dwords rep movs dword ptr es:[edi], dword ptr ds:[esi] and eax,3 mov ecx,eax rep movs byte ptr es:[edi], byte ptr ds:[esi] pop ds ;; free the selector that came back with GlobalAlloc xor eax,eax cCall farAssociateSelector32, cCall IFreeSelector, ;; Map the original selector to this new block mov eax,NewArena mov edx,[eax].pga_address mov ebx,[eax].pga_size dec ebx mov ax,dx shr edx,16 cCall far_set_physical_address, mov eax,NewArena cCall farAssociateSelector32, mov cx,cSel mov dx,selector rd13: dec cx push bx push cx push dx cCall SetSelectorLimit, pop dx pop cx pop bx add dx,DSC_LEN ; advance to the next selector jcxz rd14 jmp short rd13 rd14: ;; Fix some values in the new arena from old arena mov eax,NewArena mov ebx,OldArena mov ecx,dword ptr [ebx].pga_handle mov dword ptr [eax].pga_handle,ecx mov ecx,dword ptr [ebx].pga_count dec ecx mov dword ptr [eax].pga_count,ecx and byte ptr [eax].pga_flags, NOT GAH_PHANTOM ;; Free the dib cCall FreeHeapDib, ; Now check if we are operating on a local heap. If we so change the ; LocalNotifyDiB to LocalNotify. mov edx, NewArena push selector pop es xor edi,edi mov di,word ptr es:[pLocalHeap] or di,di jz rd_15 cmp edi,ds:[edx].pga_size jae rd_15 ; Its not a local heap cmp word ptr es:[di].li_sig,LOCALHEAP_SIG ; es:li_sig == LH jne rd_15 mov word ptr es:[di].li_notify,codeOFFSET LocalNotifyDefault mov word ptr es:[di].li_notify+2,codeBase rd_15: mov eax,1 jmp short rd_exit rd_fail: xor eax,eax rd_exit: pop es pop fs pop ebx pop ecx cEnd cProc DibRealloc, parmW Selector parmW NewSize cBegin SetKernelDSNRes push ebx mov ds,pGlobalHeap cCall far_get_arena_pointer32, or eax,eax jz dr20 movzx ebx,NewSize mov ds:[eax].pga_size,bx add ebx,ds:[eax].pga_address mov eax,ds:[eax].pga_next mov dword ptr ds:[eax].pga_address,ebx mov bx,NewSize dec bx cCall SetSelectorLimit, mov ax,Selector jmp short drexit dr20: xor ax,ax drexit: pop ebx cEnd sEnd NRESCODE end