PAGE ,132 TITLE Windows Protect Mode Routines .list include kernel.inc include protect.inc include pdb.inc include newexe.inc .list .286p 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 rept 4 movsw endm endm CheckDS Macro local okDS push ax mov ax, ds cmp ax, pGlobalHeap je okDS int 3 okDS: pop ax endm CheckLDT Macro selector if KDEBUG test selector,SEL_LDT jnz @F int 3 @@: endif Endm DPMICALL MACRO callno mov ax, callno call DPMIProc ENDM CHECKSEL MACRO selector ENDM extrn GlobalHandle:FAR extrn GlobalRealloc:FAR extrn GlobalFix:FAR extrn GlobalUnFix:FAR extrn IGlobalFix:FAR ;Far calls in this segment extrn IGlobalFlags:FAR IF KDEBUG extrn GlobalHandleNorip:FAR ELSE extrn IGlobalHandle:FAR ENDIF DataBegin ifdef WOW externW SelectorFreeBlock externW UserSelArray endif externW WinFlags extrn kr1dsc:WORD extrn kr2dsc:WORD extrn blotdsc:WORD extrn DemandLoadSel:WORD extrn temp_sel:WORD externW MyCSSeg externW selWoaPdb externW cpLowHeap externW selLowHeap externW pGlobalHeap externW SelTableLen externW MyCSAlias extrn SelTableStart:DWORD extrn sel_alias_array:WORD if ROM externW selROMTOC externW selROMLDT externW sel1stAvail endif if ROM externD lmaHiROM externD cbHiROM endif globalD lpProc,0 DataEnd DataBegin INIT RModeCallStructure STRUC RMCS_DI dw 0 dw 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 <> public MS_DOS_Name_String MS_DOS_Name_String db "MS-DOS", 0 DataEnd INIT sBegin CODE externW MyCSDS externW gdtdsc ifdef WOW externD prevInt31proc endif sEnd CODE sBegin INITCODE assumes cs,CODE ;-----------------------------------------------------------------------; ; SwitchToPMODE ; ; ; ; Entry: ; ; In Real or Virtual Mode ; ; DS -> Data Segment ; ; 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 ife ROM 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? jz @F NoPMODEj: jmp NoPMODE @@: xor bh, bh ; Set CPU type now mov bl,WF_CPU286 cmp cl, 2 ; At least a 286? jb NoPMODEj ; No, Fail je @F ; It is a 286? mov bl,WF_CPU386 cmp cl,3 ; No, 386? je @F 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 mov selWoaPdb, si ; PDB for WOA add si, 10h ; Move start on another 256 bytes xor ax, ax ; 16-bit app call [lpProc] ; Switch to PROTECTED mode jc short NoPMODEj ; No, still Real/Virtual mode mov ax, cs and al, 7 ; LDT, Ring 3 cmp al, 7 je @F jmp 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 si ; Unlock all of our memory mov bx, si ; Segment address of start of our memory mov di, es:[PDB_block_len] ; End of our memory sub di, bx ; Size of our block in paragraphs mov cpLowHeap, di ; (MAY NEED INCREMENTING!!!) xor si, si ; Calculate # bytes in SI:DI REPT 4 shl di, 1 rcl si, 1 ENDM mov cx, bx ; Convert start of block to linear xor bx, bx ; address REPT 4 shl cx, 1 rcl bx, 1 ENDM mov ax, 0602h ;BUGBUGBUGBUG int 31h ; Mark region as pageable. pop bx DPMICALL 0002h ; Convert start of memory to selector mov si, ax mov selLowHeap, ax ; Save for WOA (MAY NEED PARA LESS!!!) mov bx, selWoaPdb ; Convert WOA PDB segment to selector DPMICALL 0002h mov selWoaPdb, ax push si push es mov ax, 168Ah ; See if we have MS-DOS extensions mov si, dataOffset MS_DOS_Name_String int 2Fh cmp al, 8Ah je short BadDPMI ; No extensions, screwed mov word ptr [lpProc][0], di ; Save CallBack address mov word ptr [lpProc][2], es mov ax, 0100h ; Get base of LDT call [lpProc] jc short NoLDTParty ifndef WOW verw ax ; Writeable? else verr ax ; for WOW we can use read access endif jnz short NoLDTParty ; nope, don't bother with it mov es, MyCSAlias assumes es,CODE mov gdtdsc, ax assumes es,nothing NoLDTParty: ; Well, we'll just have to use DPMI! pop es pop si 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 ;szInadequate: ; DB 'KRNL286: 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 externFP kSYSERRORBOX call kSYSERRORBOX ;Put up the system error message externNP ExitKernel jmp ExitKernel else ; Not WOW mov dx, codeoffset szNoPMode ; call complain ; DB 'KRNL286: Unable to enter Protected Mode',7,7,7,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 ;ROM ;-----------------------------------------------------------------------; ; LDT_Init ; ; ; ; 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 LDT_Init,, cBegin ReSetKernelDS mov es, bx ; Selector for LDT if any push es ; Get random selectors smov es, ds ReSetKernelDS es assumes ds,nothing mov cx, 1 ; Argument to get_sel call get_sel mov kr1dsc, si call get_sel mov blotdsc, si call get_sel or si, SEG_RING mov DemandLoadSel, si mov ax, DSC_DATA+DSC_PRESENT; Get an array of 16 selectors cCall alloc_sel,<0000h,0BADh,0FFFFh> ; This covers 1Mb. mov kr2dsc, ax smov ds, es pop es assumes es,nothing cEnd sEnd INITCODE sBegin CODE assumes cs,CODE ;-----------------------------------------------------------------------; ; AllocSelector ; ; ; Entry: ; ; Returns: ; AX = New selector ; = 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 cProc AllocSelectorWOW, parmW selector cBegin ; same as allocselector but doesn't set the descriptor cCall inner_alloc_selector, cEnd cProc AllocSelector, parmW selector cBegin cCall inner_alloc_selector, cEnd labelFP ;-----------------------------------------------------------------------; ; AllocAlias ; ; This allocates a data alias for the passed in selector, which ; can be either code or data. The alias will track segment ; motion. ; ; Entry: ; parmW selector selector to get an alias for ; ; Returns: ; AX = selector ; = 0 failure ; ; Registers Destroyed: ; ; History: ; Sat 20-Jan-1990 23:40:32 -by- David N. Weise [davidw] ; Cleaning up. ; ; Fri 02-Dec-1988 11:04:58 -by- David N. Weise [davidw] ; Wrote it! ;-----------------------------------------------------------------------; assumes ds,nothing assumes es,nothing cProc AllocAlias, parmW selector cBegin ifdef WOW push bx ; Whitewater tool ObjDraw needs this too endif cCall inner_alloc_selector, ; 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 ;-----------------------------------------------------------------------; ; AllocDStoCSAlias ; ; This allocates a code alias for the passed in selector, which ; should be data. The alias will track segment motion. The ; passed in selector must be less than 64K. ; ; Entry: ; parmW selector selector to get an alias for ; ; Returns: ; AX = selector ; = 0 failure ; ; Registers Destroyed: ; ; History: ; Sat 20-Jan-1990 23:40:32 -by- David N. Weise [davidw] ; Cleaning up. ; ; Fri 02-Dec-1988 11:04:58 -by- David N. Weise [davidw] ; Wrote it! ;-----------------------------------------------------------------------; assumes ds,nothing assumes es,nothing cProc IAllocDStoCSAlias,, parmW data_selector cBegin ;** 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. mov ax, data_selector ;Get handle push ax 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 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 ADCA_Already_Fixed ;Yes, don't mess with it ;** Fix the memory. Note that we're only doing this for ;** 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: cCall inner_alloc_selector, if ALIASES or ax,ax jz ada_nope mov bx,data_selector call add_alias ada_nope: endif smov es,0 ; 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,data_selector cEnd ;-----------------------------------------------------------------------; ; inner_alloc_selector ; ; ; Entry: ; ; Returns: ; ; Registers Destroyed: ; ; History: ; Sat 20-Jan-1990 23:40:32 -by- David N. Weise [davidw] ; ;-----------------------------------------------------------------------; assumes ds,nothing assumes es,nothing cProc inner_alloc_selector,, parmW selector parmW sel_type localV DscBuf,DSC_LEN cBegin mov cx, 1 mov di, selector and di, not SEG_RING_MASK jnz as1 call get_sel jnz short as_exit ; We got it jmps as_exit1 as1: mov bx, selector lea di, DscBuf smov es, ss ifdef WOW DPMICALL 000Bh ; Get existing descriptor else push ds mov ds, gdtdsc push si ; Get Descriptor mov si, bx and si, not 7 MovsDsc lea di, [di-DSC_LEN] ; Restore DI pop si pop ds endif mov cl, DscBuf.dsc_hlimit and cl, 0Fh inc cl ; # selectors call get_sel jz short as_exit1 ifdef WOW cmp sel_type, 0ffffh ; called from AllocSelectorWOW ? jz as_exit ; yes . dont set descriptor endif cmp sel_type,0 ; called from AllocSelector? jz as_fill ; done if so mov al,DSC_PRESENT+DSC_DATA cmp sel_type,1 ; called from AllocAlias? jz @F or al,DSC_CODE_BIT ; called from AllocDStoCSAlias @@: mov DscBuf.dsc_access,al as_fill: mov bx, si or bl, SEG_RING call fill_in_selector_array as_exit: or si, SEG_RING as_exit1: mov ax,si smov es, 0 cEnd ;-----------------------------------------------------------------------; ; get_sel ; ; ; ; Entry: ; ; CX = # of selectors required ; ; ; ; Returns: ; ; SI = First Selector ; ; DS = LDT ; ; ZF = 0 ; ; ; ; Error Returns: ; ; SI = 0 ; ; ZF = 1 ; ; ; ; Registers Preserved: ; ; AX,BX,CX,DX,DI,ES ; ; ; ; Registers Destroyed: ; ; ; ; Calls: ; ; ; ; History: ; ; ; ;-----------------------------------------------------------------------; cProc AllocSelectorArray,, parmW nSels cBegin mov cx, nSels call get_sel mov ax, si jz asa_fail or si, SEG_RING mov bx, si mov dx, cx mov cx, DSC_DATA+DSC_PRESENT ; Mark all as Data and Present ifdef WOW fill_in_access: 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 cProc get_sel, cBegin nogen call SetKernelDSProc ; Must call procedure here ReSetKernelDS push ax push cx xor ax, ax cmp cx, 1 ; One selector only? jne gs_int31 cmp temp_sel, ax ; Have one waiting? je gs_int31 ; no, get one xchg temp_sel, ax ; Use the waiting selector jmps gs_got_sel gs_int31: DPMICALL 0000h CHECKSEL ax gs_got_sel: mov si, ax and si, not SEG_RING_MASK if KDEBUG jnz got_sel push es pusha kerror 0, popa pop es jmps gs_exit got_sel: endif mov ax, si shr ax, 2 cmp ax, SelTableLen ; Make sure we can associate it jae gs_free_sels gs_exit: mov ds, gdtdsc ; SIDE EFFECT... UnSetKernelDS gs_exit_2: pop cx pop ax or si, si ret gs_free_sels: ReSetKernelDS cmp SelTableLen, 0 je gs_exit ; Not set yet, so we are ok mov ds, gdtdsc UnSetKernelDS push bx mov bx, si ; Could not associate, so free them xor si, si or bl, SEG_RING as_free: DPMICALL 0001h lea bx, [bx+DSC_LEN] loop as_free pop bx jmps gs_exit_2 cEnd nogen ;-----------------------------------------------------------------------; ; FreeSelector ; ; free_sel ; ; FreeSelArray ; ; ; Entry: ; ; ; ; Returns: ; ; ; ; Error Returns: ; ; ; ; Registers Preserved: ; ; BX,CX,DX,DI,SI,DS,ES ; ; ; ; Registers Destroyed: ; ; ; ; Calls: ; ; ; ; History: ; ; ; ;-----------------------------------------------------------------------; assumes ds,nothing assumes es,nothing cProc IFreeSelector,, parmW selector cBegin CheckLDT selector if ALIASES mov ax,selector call delete_alias endif xor ax, ax mov es, ax ; GRRRRRRRR! cCall FreeSelArray, cEnd assumes ds,nothing assumes es,nothing cProc free_sel,, parmW selector cBegin pushf ; !! for the nonce mov bx,selector ; must be careful in gcompact ; to ignore error return if KDEBUG or bx, SEG_RING ; Ensure Table bit correct endif DPMICALL 0001h popf cEnd assumes ds,nothing assumes es,nothing cProc FreeSelArray,, parmW selector cBegin mov bx,selector ; to ignore error return cCall GetSelectorCount mov cx, ax fsa_loop: DPMICALL 0001h lea bx, [bx+DSC_LEN] loop fsa_loop ; Any left to free cEnd ;-----------------------------------------------------------------------; ; GrowSelArray ; ; ; ; This is called from within grealloc. The point is to grow the ; ; number of contiguous selectors to tile the memory object. ; ; If we can't get a contiguous set then we attempt to find a set ; ; anywhere. ; ; ; ; Entry: ; ; ES => arena header ; ; ; ; Returns: ; ; AX => new selector array ; ; CX => new number of selectors ; ; ; ; Error Returns: ; ; ; ; Registers Preserved: ; ; BX,DX,DI,SI,DS,ES ; ; ; ; Registers Destroyed: ; ; ; ; Calls: ; ; ; ; History: ; ; ; ;-----------------------------------------------------------------------; assumes ds,nothing assumes es,nothing cProc GrowSelArray,, localV DscBuf,DSC_LEN localW oldCount cBegin mov bx, es:[ga_handle] mov di, bx cCall GetSelectorCount mov word ptr oldCount, ax mov cx, si ; New size dec cx ; Paragraph limit shr cx, 12 inc cx ; new # selectors cmp al, cl ; Same # of selectors required? je gsa_done ; yes, just return! call get_sel ; get a new selector array jz short gsa_nosels xchg si, di ; DI now new array, SI old array push es push cx and bx, SEG_RING_MASK ; Ring bits or bx, di ; New handle mov cx, word ptr oldCount push ds ; Copy Descriptor(s) push si mov es, gdtdsc mov ds, gdtdsc and si, not 7 shl cx, 2 ; CX = 4 * Descriptors = words to copy rep movsw pop si pop ds ifdef WOW ; set the descriptors push bx mov cx, word ptr oldCount or bx, SEG_RING_MASK ; start selector DPMICALL WOW_DPMIFUNC_0C pop bx endif; WOW pop cx pop es SetKernelDS mov ds, pGlobalHeap UnSetKernelDS cCall AssociateSelector, mov es:[ga_handle], bx cCall AssociateSelector, jmps gsa_done gsa_nosels: xor bx, bx ; Indicate failure gsa_done: mov ax, bx or ax, ax ; Indicate success gsa_ret: cEnd assumes ds, nothing assumes es, nothing cProc PreallocSel, cBegin nogen push ds push cx push si mov cx, 1 call get_sel call SetKernelDSProc ReSetKernelDS mov temp_sel, si or si, si ; Set flags for caller pop si pop cx pop ds UnSetKernelDS ret cEnd nogen ;-----------------------------------------------------------------------; ; alloc_sel ; ; alloc_data_sel ; ; ; Entry: ; ; parmD Address 32 bit address ; ; parmW Limit limit in paragraphs (limit of 1 meg) ; ; AX = flags alloc_sel only ; ; ; ; Returns: ; ; AX = new selector ; ; ; ; Error Returns: ; ; AX = 0 ; ; ; ; Registers Preserved: ; ; AX,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. ; ;-----------------------------------------------------------------------; assumes ds, nothing assumes es, nothing if ROM public far_alloc_data_sel16 far_alloc_data_sel16 equ this far endif cProc far_alloc_data_sel, parmD Address parmW Limit cBegin cCall alloc_data_sel, cEnd if ROM public alloc_data_sel16 alloc_data_sel16 equ this near endif cProc alloc_data_sel, ; parmD Address ; parmW Limit cBegin nogen mov ax, DSC_DATA+DSC_PRESENT errn$ alloc_sel cEnd nogen cProc alloc_sel,, parmD Address parmW Limit localV DscBuf,DSC_LEN cBegin mov cx, 1 test al, DSC_PRESENT jz as_oneonly mov cx, Limit ; Calculate how many selectors required add cx, 0FFFh rcr cx, 1 ; 17 bitdom shr cx, 11 as_oneonly: call get_sel jz short a_s_exit mov bx, si ; Selector in bx for DPMI or bl, SEL_LDT lea di, DscBuf smov es, ss ; es:di points to descriptor buffer push ax ; Save access word mov ax, Address.lo ; Set descriptor base mov DscBuf.dsc_lbase, ax mov ax, Address.hi mov DscBuf.dsc_mbase, al mov DscBuf.dsc_hbase, ah pop ax ; Access word test al, DSC_PRESENT ; If selector not present, limit is jnz short set_everything ; as passed, not a paragraph count mov word ptr DscBuf.dsc_access, ax mov ax, word ptr Limit mov DscBuf.dsc_limit, ax ifdef WOW DPMICALL 000Ch ; Fill in our stuff in the descriptor else push ds push bx ; Set Descriptor mov ds, gdtdsc 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 endif; WOW jmps as_done set_everything: dec cl and ah, not 0Fh ; Zero limit 19:16 or ah, cl ; Fill in limit 19:16 inc cl mov word ptr DscBuf.dsc_access, ax mov ax, Limit shl ax, 4 ; Convert paragraphs to byte limit dec ax mov DscBuf.dsc_limit, ax call fill_in_selector_array as_done: or si, SEG_RING a_s_exit: mov ax, si cEnd ;-----------------------------------------------------------------------; ; fill_in_selector_array ; ; ; ; Entry: ; ; AX = size of object in paragraphs ; ; DH = Discard bit for descriptors ; ; DL = Access bits ; ; CX:BX = 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: ; ; ; ;-----------------------------------------------------------------------; assumes ds, nothing assumes es, nothing cProc fill_in_selector_array, cBegin nogen CheckLDT bl push ds push es:[di].dsc_limit ; Save limit for last selector SetKernelDS test WinFlags, WF_CPU286 ; protect mode on a 286? jz next_sel mov es:[di].dsc_limit, 0FFFFh ; Others get 64k limit on 286 next_sel: cmp cx, 1 ; Last selector? jne fsa_not_last pop es:[di].dsc_limit ; yes, get its limit fsa_not_last: DPMICALL 000Ch ; Set this descriptor 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 dec es:[di].dsc_hlimit ; subtract 64kb from limit loop next_sel pop ds ret cEnd nogen ;-----------------------------------------------------------------------; ; GetSelectorBase ; get_physical_address ; ; ; Entry: ; ; Returns: ; DX:AX 32 bit physical address ; Registers Destroyed: ; none ; ; 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 CheckLDT bl ifdef WOWJUNK DPMICALL 0006h mov ax, dx mov dx, cx else push ds ; Get Segment Base Address mov ds, gdtdsc and bl, not 7 mov ax, ds:[bx].dsc_lbase mov dl, ds:[bx].dsc_mbase mov dh, ds:[bx].dsc_hbase pop ds endif; WOW pop cx pop bx 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 set_physical_address,, parmW selector cBegin CheckLDT selector push di push ax ; save low bits of address mov bx, selector call GetSelectorCount mov di, ax mov cx, dx ; CX:DX has new address pop dx set_bases: DPMICALL 0007h ; Set selector base lea bx, [bx+DSC_LEN] ; On to next selector inc cx ; Add 64k to base dec di jnz set_bases pop di 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_sel_limit ; SIDE EFFECT: descriptor bases and access are set based ; on the first in the array ; ; 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 es push di push bx ; Get existing descriptor smov es, ss lea di, DscBuf mov bx, selector CheckLDT bl ifdef WOW DPMICALL 000Bh else push ds ; Get Descriptor mov ds, gdtdsc push si mov si, bx and si, not 7 MovsDsc lea di, [di-DSC_LEN] ; Restore DI pop si pop ds endif; WOW pop bx mov dx, word ptr [DscBuf.dsc_access] and dh, 0F0h ; Zap old hlimit bits sub bx, 1 ; Turn length into linit sbb cx, 0 and cx, 0Fh ; Get bits 19:16 of new limit or dh, cl ; Set new hlimit bits mov word ptr DscBuf.dsc_access, dx mov DscBuf.dsc_limit, bx mov bx, Selector jcxz ssl_set_limit1 ; Only one, fast out inc cx ; Turn CX into selector count call fill_in_selector_array jmps ssl_done ssl_set_limit1: ; Fast out for one only ifdef WOW DPMICALL 000Ch else push ds push bx ; Set Descriptor mov ds, gdtdsc 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 endif; WOW ssl_done: pop di pop es smov ss,ss ; It might be SS we're changing cEnd ;-----------------------------------------------------------------------; ; mark_sel_NP ; ; ; 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_NP, parmW selector parmW owner localV DscBuf,DSC_LEN cBegin push es push ax push bx push di ifdef WOW lea di, DscBuf smov es, ss mov bx, selector DPMICALL 000Bh and DscBuf.dsc_access, not DSC_PRESENT or DscBuf.dsc_hlimit, DSC_DISCARDABLE mov ax, owner mov DscBuf.dsc_owner, ax DPMICALL 000Ch else push ds ; Get Descriptor mov ds, gdtdsc mov bx, selector and bl, not 7 and [bx].dsc_access, not DSC_PRESENT or [bx].dsc_hlimit, DSC_DISCARDABLE mov ax, owner mov [bx].dsc_owner, ax pop ds endif; WOW SetKernelDS mov ds, pGlobalHeap UnSetKernelDS cCall AssociateSelector, pop di pop bx pop ax pop es cEnd ;-----------------------------------------------------------------------; ; mark_sel_PRESENT ; ; This little routine is called from grealloc, specifically ; racreate. ; ; Entry: ; parmW arena_sel ; parmW selector ; ; Returns: ; SI = selector to client area (may have changed) ; ; Registers Destroyed: ; ; History: ; Tue 06-Feb-1990 00:29:56 -by- David N. Weise [davidw] ; Cleaning up tony's int 1's way too late. ; ; Fri 15-Jul-1988 21:37:22 -by- David N. Weise [davidw] ;-----------------------------------------------------------------------; assumes ds,nothing assumes es,nothing cProc mark_sel_PRESENT,, parmW arena_sel parmW selector localV DscBuf,DSC_LEN cBegin push es smov es, ss lea di, DscBuf ; ES:DI -> descriptor buffer mov bx, selector ifdef WOW DPMICALL 000Bh ; Get old descriptor else push ds ; Get Descriptor mov ds, gdtdsc push si mov si, bx and si, not 7 MovsDsc lea di, [di-DSC_LEN] ; Restore DI pop si pop ds endif; WOW or DscBuf.dsc_access, DSC_PRESENT mov ds, arena_sel mov bl, DscBuf.dsc_hlimit and bl, 0Fh ; Current number of selectors - 1 inc bl mov ax, ds:[ga_size] mov cx, ax dec cx shr cx, 12 ; New number of selectors - 1 inc cl sub bl, cl jz go_ahead ; Same number, just fill in array jb get_big ; More, must get more ; here to get small and DscBuf.dsc_hlimit, NOT 0Fh dec cl or DscBuf.dsc_hlimit, cl ; Put new number of selectors in limit inc cl push cx xor bh,bh ; BX = number of selectors to free shl cx,3 .errnz DSC_LEN - 8 add cx,selector ; CX = selector to start to free xchg bx,cx @@: cCall free_sel, lea bx, [bx+DSC_LEN] loop @B pop cx jmps go_ahead ; And fill in remaining selectors get_big: push ax ; # paragraphs mov bx, ds DPMICALL 0006h ; Get base address of arena add dx, 10h ; Move on to block adc cx, 0 pop bx ; # paragraphs mov ax, word ptr DscBuf.dsc_access ; Access bits in ax cCall alloc_sel, mov si, ax or ax,ax ; did we get a set? jz return_new_handle or si, SEG_RING test selector, IS_SELECTOR jnz @F StoH si HtoS selector @@: SetKernelDS mov ds, pGlobalHeap UnSetKernelDS cCall AssociateSelector, cCall FreeSelArray, ; Zap old handle jmps return_new_handle go_ahead: shl ax, 4 ; AX had length in paras dec ax ; now limit in bytes mov DscBuf.dsc_limit, ax ; Put in descriptor push cx mov bx, ds DPMICALL 0006h ; Get base address of arena add dx, 10h ; Move on to block adc cx, 0 mov DscBuf.dsc_lbase, dx mov DscBuf.dsc_mbase, cl mov DscBuf.dsc_hbase, ch pop cx ; # selectors mov bx, selector call fill_in_selector_array mov si, selector ; return old selector in SI return_new_handle: pop es cEnd ;-----------------------------------------------------------------------; ; alloc_data_sel_below ; ; ; Entry: ; ; Returns: ; ; Registers Destroyed: ; ; History: ; Sat 09-Jul-1988 19:10:14 -by- David N. Weise [davidw] ; ;-----------------------------------------------------------------------; assumes ds,nothing assumes es,nothing cProc alloc_data_sel_below,, parmW selector parmW paras cBegin mov bx, paras xor cx, cx rept 4 shl bx, 1 rcl cx, 1 endm cCall get_physical_address, sub ax, bx sbb dx, cx cCall alloc_data_sel, cEnd ;-----------------------------------------------------------------------; ; alloc_data_sel_above ; ; ; Entry: ; ; Returns: ; ; Registers Destroyed: ; ; History: ; Sat 09-Jul-1988 19:10:14 -by- David N. Weise [davidw] ; ;-----------------------------------------------------------------------; assumes ds,nothing assumes es,nothing cProc alloc_data_sel_above,, parmW selector parmW paras cBegin mov bx, paras xor cx, cx rept 4 shl bx, 1 rcl cx, 1 endm cCall get_physical_address, add ax, bx adc dx, cx cCall alloc_data_sel, 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 cCall get_physical_address, mov cx, dx mov bx, ax cCall get_physical_address, cmp cx, dx jne csa_done cmp bx, ax csa_done: cEnd ;-----------------------------------------------------------------------; ; get_arena_pointer ; ; ; Entry: ; ; Returns: ; ; Registers Destroyed: ; ; History: ; Sat 09-Jul-1988 20:11:27 -by- David N. Weise [davidw] ; ;-----------------------------------------------------------------------; assumes ds,nothing assumes es,nothing cProc far_get_arena_pointer, parmW selector cBegin cCall get_arena_pointer, cEnd cProc get_arena_pointer, parmW selector cBegin push bx push ds push es mov bx, selector cCall get_selector_association ReSetKernelDS es if ROM test al,1 ; If the low bit isn't set jnz @f ; then it's either 0 or the xor ax,ax ; special ROM owner selector jmps gap_exit ; (see Get/SetROMOwner) @@: endif if KDEBUG or ax, ax jz gap_exit mov ds, ax ; Sanity checks: cmp ds:[ne_magic], NEMAGIC je gap_exit cmp ds:[0], 020CDh ; PSP - not a very good check, je gap_exit ; but OK for DEBUG push si mov si, ds:[ga_handle] ; Make sure handle matches sel_check si or si, si jz short gap_match ; Boot time... sub bx, word ptr SelTableStart shl bx, 2 cmp bx, si je short gap_match xor ax, ax ; put back in 5 feb 90, alias avoided ;;; xor ax, ax ; Removed - may be an alias! gap_match: pop si endif ; KDEBUG gap_exit: pop es pop ds pop bx cEnd ;-----------------------------------------------------------------------; ; AssociateSelector ; ; Put the arena pointer or owner in the selector table slot ; corresponding to the given selector. ; ; ; Entry: ; ; Returns: ; ; Registers Destroyed: ; flags ; ; History: ; ;-----------------------------------------------------------------------; assumes ds,nothing assumes es,nothing cProc FarAssociateSelector, parmW Selector parmW ArenaSel cBegin cCall AssociateSelector, cEnd cProc AssociateSelector,, parmW selector parmW ArenaSel cBegin SetKernelDS es CheckDS ; DS must bp pGlobalHeap mov bx, selector and bl, NOT SEG_RING_MASK shr bx, 2 ; 2 bytes per selector: divide by 4 if KDEBUG cmp bx, SelTableLen ; More sanity jb @F INT3_WARN jmps bad @@: endif add bx, word ptr SelTableStart mov ax, ArenaSel if KDEBUG or ax, ax ; Zero means deleting entry jz okay CheckLDT al ; Ensure we won't GP fault later okay: endif mov ds:[bx], ax ; Finally fill in table entry bad: cEnd ;-----------------------------------------------------------------------; ; get_selector_association ; ; Returns the arena pointer or owner field from the selector table that ; was set by AssociateSelector. ; ; ; Entry: ; BX = selector to get associated arena pointer/owner ; ; Returns: ; AX = arena pointer/owner or 0 ; DS = pGlobalHeap ; ES = Kernel DS ; ; Registers Destroyed: ; BX, flags ; ; History: ; ;-----------------------------------------------------------------------; assumes ds,nothing assumes es,nothing cProc get_selector_association, cBegin nogen SetKernelDS es mov ds, pGlobalHeap and bl, NOT SEG_RING_MASK shr bx, 2 ; 2 bytes per selector: divide by 4 if ROM ;------------------------------- cmp bx, SelTableLen ; Selector in range? Make this check jb gsa_in_range ; even if not debug kernel. xor ax,ax ; No, just fail jmps gsa_exit gsa_in_range: else ;ROM ------------------------ if KDEBUG cmp bx, SelTableLen ; Selector in range? jb @F INT3_WARN xor ax, ax ; No, just fail jmps gsa_exit @@: endif endif ;ROM ------------------------ add bx, word ptr SelTableStart mov ax, ds:[bx] ; Get associated value gsa_exit: ret cEnd nogen ;-----------------------------------------------------------------------; ; pdref ; ; ; ; Dereferences the given global handle, i.e. gives back abs. address. ; ; ; ; Arguments: ; ; DX = selector ; ; DS:DI = BURGERMASTER ; ; ; ; Returns: ; ; ES:DI = address of arena header ; ; AX = address of client data ; ; CH = lock count or 0 for fixed objects ; ; CL = flags ; ; SI = handle, 0 for fixed objects ; ; ; ; Error Returns: ; ; ZF = 1 if invalid or discarded ; ; AX = 0 ; ; BX = owner of discarded object ; ; ; ; Registers Preserved: ; ; ; ; Registers Destroyed: ; ; ; ; Calls: ; ; ghdref ; ; ; ; 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 pd_exit ; yes, return 0 cCall GetAccessWord, ; Get the access bits or ax, ax jz pd_totally_bogus ; We should beef up the check for a valid discarded sel. xor cx,cx test ah, DSC_DISCARDABLE jz pd_not_discardable or cl,GA_DISCARDABLE ; Discardable, is it code? test al,DSC_CODE_BIT jz pd_not_code or cl,GA_DISCCODE pd_not_code: pd_not_discardable: test al,DSC_PRESENT jnz pd_not_discarded ; object discarded or cl,HE_DISCARDED ife RING-1 or si, SEG_RING+1 ; Handles are RING 2 else or si, SEG_RING-1 ; Handles are RING 2 endif cCall get_arena_pointer, ; get the owner mov bx, ax xor ax,ax jmps pd_exit pd_not_discarded: if KDEBUG or si, SEG_RING ; For the sel_check later endif cCall get_arena_pointer, or ax, ax jz pd_nomatch mov es, ax mov ax, es:[ga_handle] ; The real thing mov si, ax cmp ax, dx ; Quick check - handle in header je pd_match ; matches what we were given? test dl, IS_SELECTOR ; NOW, we MUST have been given jz pd_totally_bogus ; a selector!! test al, GA_FIXED ; Fixed segment? jnz pd_nomatch ; Doesn't match arena header... push ax HtoS al cmp ax, dx ; Selector must match pop ax jne pd_nomatch pd_match: or cl, es:[ga_flags] and cl, NOT HE_DISCARDED ; same as GA_NOTIFY!! test al, GA_FIXED jnz pd_fixed mov ch, es:[ga_count] HtoS al ; Back to ring 1 pd_exit: or ax,ax ret pd_totally_bogus: if KDEBUG or dx,dx jnz dref_invalid pd_null_passed: endif xor dx,dx pd_nomatch: ; Handle did not match... mov ax, dx ; Must be an alias... pd_fixed: xor si, si xor dx, dx jmps pd_exit if KDEBUG dref_invalid: push ax kerror ERR_GMEMHANDLE,,0,dx pop ax jmps pd_null_passed endif cEnd nogen ;-----------------------------------------------------------------------; ; get_rover_2 ; ; ; ; Entry: ; ; ; ; Returns: ; ; ; ; 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 mov bx, es lea di, DscBuf smov es, ss ifdef WOW DPMICALL 000Bh ; Get source descriptor else push ds ; Get Descriptor mov ds, gdtdsc push si mov si, bx and si, not 7 MovsDsc lea di, [di-DSC_LEN] ; Restore DI pop si pop ds endif; WOW SetKernelDS es mov bx, kr2dsc ; Will set kr2 to point there or bl, SEG_RING mov word ptr DscBuf.dsc_access, DSC_PRESENT+DSC_DATA mov DscBuf.dsc_limit, 0FFFFh smov es, ss UnSetKernelDS es ifdef WOW DPMICALL 000Ch else push ds mov ds, gdtdsc 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 endif; WOW mov es, bx cEnd ;-----------------------------------------------------------------------; ; get_blotto ; ; ; Entry: ; AX = arena header ; ; Returns: ; ; Registers Destroyed: ; ; History: ; Sun 31-Jul-1988 16:20:53 -by- David N. Weise [davidw] ; ;-----------------------------------------------------------------------; assumes ds,nothing assumes es,nothing cProc get_blotto,, localV DscBuf,DSC_LEN cBegin mov bx, ax lea di, DscBuf smov es, ss ifdef WOW DPMICALL 000Bh ; Get source descriptor else push ds ; Get Descriptor mov ds, gdtdsc push si mov si, bx and si, not 7 MovsDsc lea di, [di-DSC_LEN] ; Restore DI pop si pop ds endif SetKernelDS es mov bx, blotdsc ; Will set kr2 to point there or bl, SEG_RING mov word ptr DscBuf.dsc_access, DSC_PRESENT+DSC_DATA mov DscBuf.dsc_limit, 0FFFFh mov DscBuf.dsc_hlimit, 0Fh add DscBuf.dsc_lbase, 10h ; Move on to object from arena adc DscBuf.dsc_mbase, 0 adc DscBuf.dsc_hbase, 0 smov es, ss UnSetKernelDS es ifdef WOW DPMICALL 000Ch ; Set new descriptor else push ds mov ds, gdtdsc 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 endif ;WOW mov ax, bx ; Return new selector cEnd ;-----------------------------------------------------------------------; ; get_temp_sel ; far_get_temp_sel ; ; ; Entry: ; ; Returns: ; ; Registers Destroyed: ; ; History: ; Mon 08-Aug-1988 19:14:45 -by- David N. Weise [davidw] ; ;-----------------------------------------------------------------------; assumes ds,nothing assumes es,nothing cProc far_get_temp_sel, cBegin nogen cCall get_temp_sel ret cEnd nogen cProc get_temp_sel,, localV DscBuf,DSC_LEN cBegin mov cx, 1 call get_sel mov ax, si jz gts_exit mov bx, es smov es, ss lea di, DscBuf ifdef WOW DPMICALL 000Bh ; Get existing descriptor else push ds ; Get Descriptor mov ds, gdtdsc push si mov si, bx and si, not 7 MovsDsc lea di, [di-DSC_LEN] ; Restore DI pop si pop ds endif ; WOW mov DscBuf.dsc_access,DSC_PRESENT+DSC_DATA mov DscBuf.dsc_limit,0ffffh IFNDEF WOW or DscBuf.dsc_hlimit, 0Fh ; Max length ; bugbug daveh ENDIF mov bx, si or bl, SEG_RING ifdef WOW DPMICALL 000Ch ; Set new descriptor else push ds mov ds, gdtdsc 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 endif ; WOW mov es, bx ; and return selector in ES gts_exit: cEnd cProc far_free_temp_sel, parmW selector cBegin cCall free_sel, cEnd ;-----------------------------------------------------------------------; ; 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 smov es, ss lea di, DscBuf mov bx, sourcesel ifdef WOW DPMICALL 000Bh else push ds ; Get Descriptor mov ds, gdtdsc push si mov si, bx and si, not 7 MovsDsc lea di, [di-DSC_LEN] ; Restore DI pop si pop ds endif ; WOW xor DscBuf.dsc_access, DSC_CODE_BIT mov bx, destsel ifdef WOW DPMICALL 000Ch else push ds mov ds, gdtdsc 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 endif; WOW mov ax, bx smov es, 0 cEnd if 0 ;-----------------------------------------------------------------------; ; pmnum ; ; ; ; Enumerates the allocated selectors in the GDT with the ; ; specified discard level. ; ; ; ; Arguments: ; ; SI = zero first time called. Otherwise contains a pointer ; ; to the last handle returned. ; ; CX = #handles remaining. Zero first time called. ; ; DI = address of local arena information structure. ; ; ; ; Returns: ; ; SI = address of handle table entry ; ; CX = #handles remaining, including the one returned. ; ; ZF = 1 if SI = 0 and no more handle table entries. ; ; ; ; Error Returns: ; ; ; ; Registers Preserved: ; ; ; ; Registers Destroyed: ; ; AX ; ; ; ; Calls: ; ; nothing ; ; ; ; History: ; ; ; ; Tue Oct 14, 1986 04:19:15p -by- David N. Weise [davidw] ; ; Added this nifty comment block. ; ;-----------------------------------------------------------------------; cProc pmnum, cBegin nogen or si,si ; Beginning of enumeration? jnz lcdhenext ; No, return next handle mov ax,[di].hi_htable ; Yes, start with last handle table block lcdhtloop: mov si,ax ; SI = address of handle table block or si,si ; Any more handle table blocks? jz lcdheall ; No, return zero lodsw ; Get # handles in this block errnz ht_count mov cx,ax ; into CX lcdheloop: ; Loop to process each handle table entry mov ax,word ptr [si].lhe_flags errnz errnz <2-lhe_flags> errnz <3-lhe_count> inc ax ; Free handle? jz lcdhenext ; Yes, skip this handle errnz errnz dec ax cmp [di].hi_dislevel,0 ; Enumerating all allocated handles? je lcdheall ; Yes, return this handle test al,LHE_DISCARDED ; No, handle already discarded? jnz lcdhenext ; Yes, skip this handle and al,LHE_DISCARDABLE ; Test if DISCARDABLE cmp [di].hi_dislevel,al ; at the current discard level jne lcdhenext ; No, skip this handle or ah,ah ; Is handle locked? jnz lcdhenext ; Yes, skip this handle lcdheall: or si,si ; No, then return handle to caller ret ; with Z flag clear lcdhenext: lea si,[si].SIZE LocalHandleEntry ; Point to next handle table entry errnz loop lcdheloop ; Process next handle table entry lodsw ; end of this block, go to next jmp lcdhtloop cEnd nogen 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 a megabyte. ; ; 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 ifdef WOW DPMICALL 000Bh ; Pick up old descriptor else push ds ; Get Descriptor mov ds, gdtdsc push si mov si, bx and si, not 7 MovsDsc lea di, [di-DSC_LEN] ; Restore DI pop si pop ds endif ; WOW 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, 0FFF0h 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] adc dx, cx ifdef WOW lptr_mustset: endif mov cl, DscBuf.dsc_hlimit ; Calculate # selectors now in array and cl, 0Fh xor ch, ch inc cx ifdef WOW test flBaseSetting, LPTRADDWOW_SETBASE jz lptr_dontset cmp RefSelector, 0 jz @F mov bx, RefSelector 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], 0fff0h 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 jmps 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 mov bx, selector mov dx, selbase.lo mov cx, selbase.hi ifdef WOW DPMICALL 0007h else push ds mov ds, gdtdsc 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 mov ax, 0 jc ssb_exit mov ax, selector ; Return selector ssb_exit: cEnd ;-----------------------------------------------------------------------; ; GetSelectorLimit ; ; Gets 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 localV DscBuf,DSC_LEN cBegin mov bx, selector ifdef WOW lea di, DscBuf smov es, ss DPMICALL 000Bh xor dx, dx mov ax, DscBuf.dsc_limit mov dl, DscBuf.dsc_hlimit and dx, 0Fh ; AND out flags else push ds ; Get Descriptor mov ds, gdtdsc and bl, not 7 mov ax, [bx].dsc_limit mov dl, [bx].dsc_hlimit and dx, 0Fh ; AND out flags pop ds endif ; WOW 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 mov bx, selector ifdef WOW push di lea di, DscBuf smov es, ss DPMICALL 000Bh mov ax, word ptr sellimit[0] mov DscBuf.dsc_limit, ax mov al, byte ptr sellimit[2] and al, 0Fh and DscBuf.dsc_hlimit, 0F0h or DscBuf.dsc_hlimit, al DPMICALL 000Ch pop di else push ds ; Get Descriptor mov ds, gdtdsc push si mov si, bx and si, not 7 mov ax, sellimit.lo mov [si].dsc_limit, ax mov ax, sellimit.hi and al, 0Fh and [si].dsc_hlimit, 0F0h or [si].dsc_hlimit, al pop si pop ds 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 localV DscBuf,DSC_LEN cBegin cCall GetAccessWord, 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 mov bx, selector ifdef WOW push di lea di, DscBuf smov es, ss DPMICALL 000Bh ; Set new access rights mov word ptr DscBuf.dsc_access, cx DPMICALL 000Ch pop di else push ds ; Get Descriptor mov ds, gdtdsc and bx, not 7 mov word ptr [bx].dsc_access, cx pop ds endif ;WOW xor ax,ax ; for now always return success sar_exit: cEnd ; ; Direct GDT access is really helpful here - you are supposed ; to use LAR to get the high access bits, but this ; cannot be done on a 286 where we are STILL using ; these bits in a 386 compatible manner ; cProc GetAccessWord, parmW selector localV DscBuf,DSC_LEN cBegin push bx push es cmp gdtdsc, 0 ; Do we have LDT access? je do_it_the_really_slow_way ; no, must make DPMI call mov es, gdtdsc ; Go grab it out of the LDT mov bx, selector sel_check bl mov ax, word ptr es:[bx].dsc_access jmps gaw_exit do_it_the_really_slow_way: push di lea di, DscBuf smov es, ss mov bx, selector DPMICALL 000Bh mov ax, word ptr DscBuf.dsc_access pop di gaw_exit: pop es pop bx gaw_exit1: cEnd ; ; Setting it is WORSE.... ; cProc SetAccessWord,, parmW selector parmW access localV DscBuf,DSC_LEN cBegin mov bx, selector ifndef WOW ; For WOW we have to call DMPI, LATER for mips this should party directly cmp gdtdsc, 0 je slow_again mov es, gdtdsc ; Go stuff it in the LDT sel_check bl mov ax, access mov word ptr es:[bx].dsc_access, ax jmps saw_exit endif ; WOW slow_again: ; ; The DPMI guys changed their mind, NOW call 9h ; WILL set the AVL bit in the descriptor on ; all implementations. ; sel_check bl push cx mov cx, access DPMICALL 0009h pop cx saw_exit: cEnd ; ; Selector in BX ; cProc GetSelectorCount, cBegin nogen cmp gdtdsc, 0 je @F push ds push bx mov ds, gdtdsc sel_check bl mov al, ds:[bx].dsc_hlimit pop bx pop ds and ax, 0Fh inc al ret @@: push es push di sub sp, DSC_LEN mov di, sp smov es, ss DPMICALL 000Bh mov al, es:[di].dsc_hlimit add sp, DSC_LEN pop di pop es and ax, 0Fh inc al ret cEnd nogen ;-----------------------------------------------------------------------; ; GlobalPageLock ; ; Page locks the memory associated with the Handle. ; ; Entry: ; parmW handle ; ; Returns: ; AX = new lock count ; ; History: ; Fri 16-Feb-1990 02:13:09 -by- David N. Weise [davidw] ; Should it or shouldn't it? At the very least it must lock ; the object to be consitent with 386pmode. ; ; Wed 31-May-1989 22:14:21 -by- David N. Weise [davidw] ; Wrote it! ;-----------------------------------------------------------------------; assumes ds,nothing assumes es,nothing cProc IGlobalPageLock,, parmW handle cBegin cCall GlobalFix, cCall GetSelectorLimit, mov si, dx mov di, ax cCall get_physical_address, mov bx, dx mov cx, ax DPMICALL 0600h mov ax, 1 cEnd ;-----------------------------------------------------------------------; ; GlobalPageUnlock ; ; Page unlocks the memory associated with the Handle. ; ; Entry: ; parmW handle ; ; Returns: ; AX = new lock count ; ; History: ; Fri 16-Feb-1990 02:13:09 -by- David N. Weise [davidw] ; Should it or shouldn't it? At the very least it must unlock ; the object to be consitent with 386pmode. ; ; Wed 31-May-1989 22:14:21 -by- David N. Weise [davidw] ; Wrote it! ;-----------------------------------------------------------------------; assumes ds,nothing assumes es,nothing cProc IGlobalPageUnlock,, parmW handle cBegin cCall GlobalUnFix, cCall GetSelectorLimit, mov si, dx mov di, ax cCall get_physical_address, mov bx, dx mov cx, ax DPMICALL 0601h xor ax,ax ; page lock count is zero cEnd if ROM ;---------------------------------------------------------------- ;----------------------------------------------------------------------- ; ChangeROMHandle ; ; Changes the handle of an allocated memory block. Used when loading ; segments from ROM to RAM so RAM copy can use the handle expected by ; other ROM code. ; ; Entry: ; parmW hOld ; parmW hNew ; ; Returns: ; AX = hNew if successful, 0 if not ; ; History: ; ;----------------------------------------------------------------------- assumes ds,nothing assumes es,nothing cProc ChangeROMHandle,, parmW hOld parmW hNew localV DscBuf,DSC_LEN cBegin mov bx,hOld ; Get arena pointer for old handle cCall get_arena_pointer, or ax,ax if KDEBUG jnz @f INT3_WARN jmps ch_ret @@: else jz ch_ret endif push ax mov si, bx and bx, SEG_RING_MASK ; Ring bits or bx, hNew ; New handle smov es, ss lea di, DscBuf xchg bx ,si DPMICALL 000Bh ; Get old descriptor xchg bx, si DPMICALL 000Ch ; Set new descriptor pop es ; es -> arena (or owner) SetKernelDS mov ds, pGlobalHeap UnSetKernelDS cCall AssociateSelector, ; Old sel has not association test DscBuf.dsc_access,DSC_PRESENT ; Change handle in arena jz crh_np ; if selector is present mov es:[ga_handle], bx crh_np: cCall AssociateSelector, ; New sel associated with this ; arena or owner cCall FreeSelArray, ; Free old selector mov ax,bx ch_ret: cEnd ;----------------------------------------------------------------------- ; CloneROMSelector ; ; Changes the base and limit of the clone selector to point to the ; ROM selector's original ROM segment. ROM segment selectors may be ; changed when loading a ROM segment to RAM. ; ; Entry: ; parmW selROM ; parmW selClone ; ; Returns: ; ; History: ; ;----------------------------------------------------------------------- assumes ds,nothing assumes es,nothing cProc CloneROMSelector,, parmW selROM parmW selClone localV DscBuf,DSC_LEN cBegin SetKernelDS es mov ax,selROMLDT mov es,selROMToc assumes es,nothing mov bx,selROM if KDEBUG cmp bx,es:[FirstROMsel] ; sanity checks to make sure jae @f ; selector is within ROM range INT3_WARN @@: push bx and bl,not SEG_RING_MASK sub bx,es:[FirstROMsel] shr bx,3 cmp bx,es:[cROMsels] jbe @f INT3_WARN @@: pop bx endif mov si, bx and si, NOT SEG_RING_MASK sub si, es:[FirstROMsel] ; si = offset in ROM LDT of descriptor mov ds, ax ; copy ROM desciptor to stack buffer smov es, ss lea di, DscBuf errnz <8 - DSC_LEN> movsw movsw movsw movsw mov bx, selClone ; clone descriptor to orig ROM contents lea di, DscBuf DPMICALL 000Ch SetKernelDS mov ds, pGlobalHeap UnSetKernelDS cCall AssociateSelector, ; no arena/owner currently mov ax,bx ; return with selClone in AX cEnd endif ;ROM --------------------------------------------------------- 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 cProc CheckKernelDSProc, cBegin nogen if KDEBUG cmp ax, cs:MyCSDS je dsok INT3_WARN dsok: endif ret cEnd nogen assumes ds, nothing assumes es, nothing cProc FarGetOwner,, parmW Selector cBegin cCall GetOwner, cEnd cProc GetOwner,, parmW Selector cBegin cCall get_arena_pointer, if ROM or ax,ax ; get_arena_pointer fails on jnz go_got_it ; ROM segments so give it cCall GetROMOwner, ; another try jmps go_end go_got_it: else or ax, ax jz go_end endif mov es, ax mov ax, es:[ga_owner] go_end: 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 cCall get_arena_pointer, mov es, ax push owner pop es:[ga_owner] cEnd if ROM ;---------------------------------------------------------------- ;----------------------------------------------------------------------- ; Set/GetROMOwner ; ; The Get/SetROMOwner routines use AssociateSelector and the inverse ; get_selector_association routines to track the owner of an object ; in ROM. ROM objects (like code segments and resources) don't have ; a global heap arena to store the owner's ID in. ; ; NOTE: THIS CODE DEPENDS ON WINDOWS RUNNING IN RING 1 OR 3!! The low ; bit of the associated value is set to zero to indicate the object is ; in ROM. SetROMOwner expects the owner selector to have the low bit ; set, and GetROMOwner returns the owner field with the low bit set. ; ;----------------------------------------------------------------------- assumes ds, nothing assumes es, nothing cProc FarSetROMOwner, parmW Selector parmW Owner cBegin cCall SetROMOwner, cEnd cProc SetROMOwner,, parmW Selector parmW Owner cBegin mov ax,Owner and al,NOT 1 ; mark this as a ROM selector SetKernelDS mov ds,pGlobalHeap UnSetKernelDS cCall AssociateSelector, cEnd cProc GetROMOwner,, parmW Selector cBegin mov bx,Selector cCall get_selector_association or ax,ax jz gro_exit test al,1 ; low bit off if ROM owner jnz gro_not_rom_owner or al,1 ; restore bit cleared by SetROMOwner jmps gro_exit gro_not_rom_owner: xor ax,ax gro_exit: cEnd ;-----------------------------------------------------------------------; ; IsROMObject ; ; Determines if a given selector points into the ROM area. ; ; Entry: ; selector selector to check ; ; Returns: ; AX != 0 & CY set if selector points to ROM ; AX = 0 & CY clr if selector does not point to ROM ; ; Registers Destroyed: ; none ; ; History: ;-----------------------------------------------------------------------; assumes ds,nothing assumes es,nothing cProc FarIsROMObject, parmW selector cBegin cCall IsROMObject, cEnd cProc IsROMObject,, parmW selector localV DscBuf,DSC_LEN cBegin push ds SetKernelDS if KDEBUG mov ax,selector sel_check ax endif mov bx,selector smov es,ss lea di,DscBuf DPMICALL 000Bh ; Get current descriptor mov bh,DscBuf.dsc_hbase ; is descriptor base at or mov bl,DscBuf.dsc_mbase ; above start of ROM? mov ax,DscBuf.dsc_lbase sub ax,lmaHiROM.off sbb bx,lmaHiROM.sel jc iro_not_rom sub ax,cbHiROM.off ; make sure it's not above sbb bx,cbHiROM.sel ; the end of the ROM jnc iro_not_rom mov al,1 ; in ROM range, ret AX != 0 & CY set jmps iro_exit iro_not_rom: xor ax,ax ; not in ROM, AX = 0 & CY clear iro_exit: pop ds assumes ds,nothing cEnd endif ;ROM --------------------------------------------------------- assumes ds, nothing assumes es, nothing cProc FarValidatePointer, parmD p cBegin cCall ValidatePointer,

cEnd cProc ValidatePointer, parmD p cBegin lsl ax, seg_p jnz short bad_p ; can we access this selector? cmp ax, off_p ; yes, 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 OneParaBytes ; Smaller than rotates cEnd cProc SegToSelector,, parmW smegma cBegin mov bx, smegma DPMICALL 0002h 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 mov cx, es ifdef WOW push ax lea di, DscBuf smov es, ss DPMICALL 000Bh mov DscBuf.dsc_owner, cx DPMICALL 000Ch pop ax else push ds ; Get Descriptor mov ds, gdtdsc push di mov di, bx and di, not 7 mov [di].dsc_owner, cx pop di pop ds endif ; WOW SetKernelDS mov ds, pGlobalHeap UnSetKernelDS cCall AssociateSelector, mov es, cx ; Restore ES 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 DscBuf.dsc_access, DSC_DATA mov cx,selCount dec cl and cl,00001111b or cl,DSC_DISCARDABLE mov DscBuf.dsc_hlimit, cl ; Save number of selectors here DPMICALL 000Ch ; Set it with new owner else push ds ; Get Descriptor mov ds, gdtdsc push bx and bx, not 7 mov [bx].dsc_owner, cx mov [bx].dsc_access, DSC_DATA mov cx,selCount dec cl and cl,00001111b or cl,DSC_DISCARDABLE mov [bx].dsc_hlimit, cl ; Save number of selectors here pop bx pop ds endif ; WOW SetKernelDS mov ds, pGlobalHeap UnSetKernelDS cCall AssociateSelector, ; And save in selector table cEnd ;-----------------------------------------------------------------------; ; ; Alias stuff moved out due to gross bloating of this file ; ;-----------------------------------------------------------------------; if ALIASES include aliases.asm endif ;-----------------------------------------------------------------------; ; 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 or ah, ah jz @F 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 @@: if ROM cmp al, 01h ; Free selector? jne @f push ds SetKernelDS cmp bx,sel1stAvail ; Yes, don't free selectors in pop ds ; the preallocated ROM range UnSetKernelDS jae CallServer ret @@: endif ;ROM 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 jmps CallServer @@: endif cmp al, 0Bh jne @F test bx,4 jnz xx1 ; On MIPS if Win87EM is processing an NPX exception the selector ; to Dosx's stack is being looked up here. Since it is a global ; selector the normal lookup will not find it and Win87EM will ; fault. This is solved by calling Dosx since it knows about the ; global selectors that we don't. - MarkRi [6/93] ; pop ds jmps CallServer xx1: 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 if ROM if1 %out CheckROMSelector -- fix me!! (what exactly is wrong?) endif endif if 0 ;;ROM and KDEBUG ;------------------------------------------------------------------------ ; CheckROMSelector ; ; ROM Windows debug hack to ensure that Windows code doesn't try writing ; to the ROM image. It does this by making any data selector to the ; ROM read only. ; ; Entry: ; DS:BX -> descriptor to check ; ; Returns: ; nothing ; ; Registers Destroyed: ; none ; ;------------------------------------------------------------------------ assumes ds,nothing assumes es,nothing cProc CheckROMSelector, cBegin nogen test ds:[bx].dsc_access,DSC_CODEDATA ; code or data dsc? jz crs_exit ; no, skip it test ds:[bx].dsc_access,DSC_CODE_BIT ; code? jnz crs_exit ; yes, skip it push ax push dx mov dh,ds:[bx].dsc_hbase ; is descriptor base at or mov dl,ds:[bx].dsc_mbase ; above start of ROM? mov ax,ds:[bx].dsc_lbase sub ax,lmaHiROM.off sbb dx,lmaHiROM.sel jc crs_exit1 sub ax,cbHiROM.off ; make sure it's not above sbb dx,cbHiROM.sel ; the end of the ROM jnc crs_exit1 and ds:[bx].dsc_access,NOT DSC_RW_BIT ; make it read only crs_exit1: pop dx pop ax crs_exit: ret cEnd nogen endif ;ROM and KDEBUG ifdef WOW cProc alloc_special_sel,, parmW AllocFlags parmW SelFreeBlock parmW SizeFreeBlock parmW SizeNewFreeBlock parmW AdjustedSize parmB fBaseAddressToUse localD AddressNewFreeBlock localD Address localW Limit localW cFreeBlock localW cTotalSelectors localW EachSelectorLimit cBegin ; ; this will be our ds ; mov ds, gdtdsc ; ; replace allocflags with accessword ; mov bx, AllocFlags and bx, ((GA_CODE_DATA+GA_DISCARDABLE) shl 8) + GA_DGROUP or bl, bh xor bh, bh shl bx, 1 mov ax, cs:SelAccessWord[bx] ; Pick up access rights for selector mov AllocFlags, ax ; allocflags = access rights ; ; Limit for data selectors ; mov ax, AdjustedSize dec ax mov Limit, ax ; ; compute base address for new freeblock and the first selector ; the base address is dependent on fBaseAddressToUse flag ; cCall get_physical_address, cmp fBaseAddressToUse, ga_prev jne @F mov bx, SizeNewFreeBlock xor cx,cx REPT 4 shl bx,1 rcl cx,1 ENDM add ax, bx adc dx, cx mov AddressNewFreeBlock.lo, ax mov AddressNewFreeBlock.hi, dx ; ; compute base address for first selector ; add ax, 10h adc dx, 00h mov Address.lo, ax mov Address.hi, dx jmps alloc_checkforfreeblock @@: push ax ; save base address of freeblock push dx add ax, 10h adc dx, 00h mov Address.lo, ax ; address of first selector mov Address.hi, dx pop dx pop ax mov bx, AdjustedSize xor cx,cx REPT 4 shl bx,1 rcl cx,1 ENDM add ax, bx adc dx, cx mov AddressNewFreeBlock.lo, ax mov AddressNewFreeBlock.hi, dx alloc_checkforfreeblock: ; ; check if a 'new' free block needs to be created. ; cFreeBlock = (SizeNewFreeBlock) ? 1 : 0; ; mov cFreeBlock, 0 mov cx, SizeNewFreeBlock jcxz alloc_nofreeblock mov cFreeBlock, 1 alloc_nofreeblock: ; ; start of processing ; mov cx, 1 mov ax, AllocFlags test al, DSC_PRESENT jz allocspecial_oneonly ; limit in paras mov cx, Limit ; Calculate how many selectors required add cx, 0FFFh rcr cx, 1 ; 17 bitdom shr cx, 11 allocspecial_oneonly: push cx add cx, cFreeBlock ; cFreeBlock is zero or one mov cTotalSelectors, cx ; ; the dpmi func is 04f1h. This is idential to function 00h, except that ; the descriptor base and limit are not initialized to zero. ; DPMICALL WOW_DPMIFUNC_00 pop cx jnz allocspecial_continue jmp allocspecial_exit allocspecial_continue: push ax ; save the first selector and ax, not SEG_RING mov bx, ax ; Selector in bx for DPMI mov ax, Address.lo ; Set descriptor base mov [bx].dsc_lbase, ax mov di, ax ; used later mov ax, Address.hi mov [bx].dsc_mbase, al mov [bx].dsc_hbase, ah mov ax, AllocFlags test al, DSC_PRESENT ; If selector not present, limit is jnz short allocspecial_present ; as passed, not a paragraph count allocspecial_not_present: mov word ptr [bx].dsc_access, ax mov ax, word ptr Limit mov [bx].dsc_limit, ax jmps allocspecial_done allocspecial_present: dec cl and ah, not 0Fh ; Zero limit 19:16 or ah, cl ; Fill in limit 19:16 inc cl mov word ptr [bx].dsc_access, ax mov si, ax ; save for later use mov ax, Limit shl ax, 4 ; Convert paragraphs to byte limit dec ax mov [bx].dsc_limit, ax dec cx jcxz allocspecial_done ; if sel=1 done. mov EachSelectorLimit, ax ; ax the limit from above mov al, [bx].dsc_mbase ; mov ah, [bx].dsc_hbase mov dl, [bx].dsc_hlimit push ds SetKernelDS test WinFlags, WF_CPU286 ; protect mode on a 286? pop ds push [bx].dsc_limit ; Save limit for last selector jz allocspecial_next_sel ; the result of the test above mov EachSelectorLimit, 0FFFFh ; Others get 64k limit on 286 allocspecial_next_sel: push ax mov ax, EachSelectorLimit mov [bx].dsc_limit, ax ; limit for current selector pop ax lea bx, [bx+DSC_LEN] ; On to next selector cmp cx, 1 ; Last selector? jne allocspecial_fsa_not_last pop [bx].dsc_limit ; yes, get its limit allocspecial_fsa_not_last: mov [bx].dsc_lbase, di mov word ptr [bx].dsc_access, si inc ax mov [bx].dsc_mbase, al ; Add 64kb to address mov [bx].dsc_hbase, ah dec dl mov [bx].dsc_hlimit, dl ; subtract 64kb from limit loop allocspecial_next_sel allocspecial_done: cmp cFreeBlock, 1 jne allocspecial_nofreeblock allocspecial_freeblock: mov ax, AddressNewFreeBlock.lo ; the base for freeblock mov dx, AddressNewFreeBlock.hi lea bx, [bx+DSC_LEN] ; On to next selector mov [bx].dsc_limit, 0fh ; = 1 para mov [bx].dsc_lbase, ax mov [bx].dsc_mbase, dl mov [bx].dsc_hbase, dh mov ax, DSC_DATA+DSC_PRESENT and ah, not 0Fh ; Zero limit 19:16 mov word ptr [bx].dsc_access, ax allocspecial_nofreeblock: pop si ; restore the first selector push bx mov cx, cTotalSelectors mov bx, si ; ; the dpmi func is 04f2h. This 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 DPMICALL WOW_DPMIFUNC_0C pop bx SetKernelDS ; ; sanity check. done so late because if this check was done ; somewhere eariler, we would have had to Save and Restor DS. Since ; this check would be successful most of the time, it is quite Ok ; to do it now and we would avoid unneccessary loading of DS. mov ax, bx shr ax, 2 cmp ax, SelTableLen ; Make sure we can associate it jb @F xor ax, ax ; set zero flag jmps allocspecial_exit @@: mov UserSelArray, si ; the selector for user data mov ax, bx or ax, SEG_RING ; selector of new freeblock, if one is ; created. sets nz flag. mov SelectorFreeBlock, ax ; allocspecial_exit: cEnd ;---------------------------------------------------------------------------- ; grabbed from 2gmem.asm ; ;---------------------------------------------------------------------------- SelAccessWord dw DSC_DATA+DSC_PRESENT dw (DSC_DISCARDABLE SHL 8) + DSC_DATA+DSC_PRESENT dw DSC_CODE+DSC_PRESENT dw (DSC_DISCARDABLE SHL 8) + DSC_CODE+DSC_PRESENT dw DSC_DATA+DSC_PRESENT dw (DSC_DISCARDABLE SHL 8) + DSC_DATA+DSC_PRESENT dw DSC_DATA+DSC_PRESENT dw (DSC_DISCARDABLE SHL 8) + DSC_DATA+DSC_PRESENT ;----------------------------------------------------------------------------- ; 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 sEnd CODE sBegin NRESCODE assumes CS,NRESCODE assumes DS,NOTHING assumes ES,NOTHING cProc get_sel_flags, parmW selector cBegin ; Not used in krnl286 xor ax,ax xor dx,dx cEnd cProc set_sel_for_dib, parmW selector parmW flags parmD address parmW csel cBegin ; Not used in krnl286 xor ax,ax xor dx,dx cEnd cProc RestoreDib, parmW selector parmW flags parmD address cBegin ; Not used in krnl286 xor ax,ax xor dx,dx cEnd cProc DibRealloc, parmW Selector parmW NewSize cBegin cEnd endif sEnd NRESCODE end