; PMODE v3.07 DPMI/VCPI/XMS/raw protected mode interface kernel. ; Copyright (c) 1994, Tran (a.k.a. Thomas Pytel). ; ; Changed to compile under TASM for DJGPP by m.grimrath@tu-bs.de ; Assemble case sensitive on all symbols! P386 IDEAL ASSUME cs:_TEXT, ds:DGROUP, es:nothing, ss:nothing GROUP DGROUP _DATA, _BSS ;▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒ ; Configuration options ;▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒ ; [fold] [ ; Set to one to call exception 7 through a trap gate. An improvement of ; 10% in execution speed is possible using wmemu387. ; However, if one of the pics uses ints 0 to 7 (highly unlikely but supported) ; then an IRQ7 or IRQ15 will probably crash the computer. ; Also we cannot tell 'int 7' from exception 7. FAST_FPU_EMU = 1 ; Set to 1 to have PMODE/DJ extensions to the DPMI standard. PMODEDJ_EXT = 0 ; [fold] ] ;▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒ ; Makros ;▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒ ; [fold] [ off EQU offset pdseg EQU fs ; take advantage of the 2 additional coreseg EQU gs ; segment registers! ; Macros to build up standard selectors MACRO init_sel ; Initialize selector sel_aktcnt = 0 ENDM MACRO mk_sel selec ; Add one selectors selec = sel_aktcnt*8 sel_aktcnt = sel_aktcnt+1 ENDM MACRO mk_msel selec,num ; Make multiple selectors selec = sel_aktcnt*8 sel_aktcnt = sel_aktcnt+num ENDM MACRO get_num_sel lab ; returns the current number of selectors lab = sel_aktcnt ENDM ; a 32 addressing nop (for a 386 bug) MACRO dnop DB 67h nop ENDM ; Makes a linear address from seg:ofs MACRO ptr2lin seg,ofs,r1,r2,er1,er2 mov r1,seg movzx er1,r1 shl er1,4 mov r2,ofs movzx er2,r2 add er1,er2 ENDM ; Make a segment from a linear address MACRO lin2seg segm,lin,ereg,reg IFDIF <lin>,<ereg> mov ereg,lin ENDIF shr ereg,4 mov segm,reg ENDM ; Sets a memory area to zero MACRO setmemw seg,ofs,size IFDIF <seg>,<es> push seg pop es ENDIF IFDIF <ofs>,<di> mov di,ofs ENDIF mov cx,(size) / 2 sub ax,ax cld rep stosw nop ; 386 bug ENDM ; Copies memory areas with ESI and EDI MACRO dmemcpyw sseg,sofs,dseg,dofs,size IFDIF <sofs>,<esi> mov esi,sofs ; Put this HERE, or else you can't use esp ENDIF IFDIF <dofs>,<edi> mov edi,dofs ; as macro argument ENDIF IFDIF <size>,<ecx> mov ecx,(size) / 2 ENDIF push ds es IFDIF <dseg>,<es> push dseg ENDIF IFDIF <sseg>,<ds> push sseg pop ds ENDIF IFDIF <dseg>,<es> pop es ENDIF cld DB 67h ; To use ECX, ESI and EDI rep movsw dnop ; 386 bug pop es ds ENDM ; Copies memory areas with SI and DI MACRO memcpyw sseg,sofs,dseg,dofs,size IFDIF <sofs>,<si> mov si,sofs ; Put this HERE, or else you can't use esp ENDIF IFDIF <dofs>,<di> mov di,dofs ; as macro argument ENDIF IFDIF <size>,<cx> mov cx,(size) / 2 ENDIF push ds es IFDIF <dseg>,<es> push dseg ENDIF IFDIF <sseg>,<ds> push sseg pop ds ENDIF IFDIF <dseg>,<es> pop es ENDIF cld rep movs [WORD PTR es:di],[WORD PTR ds:si] pop es ds ; these pops cover 386 bug ENDM ; to save one line of source code MACRO copy dst,src,reg mov reg,src mov dst,reg ENDM ; not to write so many lines MACRO init_dsc base,sel,limit,rights IFDIF <base>,<ax> mov ax,base ENDIF IFDIF <sel>,<bx> mov bx,sel ENDIF IFDIF <limit>,<ecx> mov ecx,limit ENDIF IFDIF <rights>,<dx> mov dx,rights ENDIF call vxr_initsetdsc ENDM ; zero extends 16 bit offset to 32, so it can be linked without 32 records MACRO do16to32 mnem,p1,p2 DB 66h ; 32 bit operand mode mnem p1,p2 DW 0 ENDM ; [fold] ] ;▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒ ; Constants and structures ;▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒ ; [fold] [ ; As you might notice, all structures start with a capital letter ; When changing the source, please keep this style! RMSTACKLEN = 0C00h ; real mode stack length, in bytes RMONESTACKLEN = 200h PMSTACKLEN = 0C00h ; protected mode stack length, in bytes PMONESTACKLEN = 200h VCPISTACKLEN = 100h ; just for switching CALLBACKS = 16 ; number of real mode callbacks NUM_EXCEPTIONS = 16 ; # of handled exceptions init_sel ; Global descriptortable mk_sel SELNULL ; NULL selector mk_sel SELCORE ; selector of entire memory space mk_sel SELCS ; Selector for Codesegment mk_sel SELDS ; Selector for Datasegment mk_sel SELREAL ; real mode attributes selector mk_sel SELALIASCS ; to write to CS mk_sel SELPRIVAT ; to access privat data mk_sel SELINT24 ; for INT 24h callback mk_sel SELVCPITSS ; TSS selector for VCPI mk_sel SELVCPI ; VCPI call code selector mk_sel SELVCPI1 mk_sel SELVCPI2 ; reserved for VCPI host mk_msel SELTASKS,NUM_EXCEPTIONS get_num_sel SYSSELECTORS ; number of system-selectors GDT_NUM_ENTRIES = 128 ; # of entries in the gdt ; A 32bit Task status structure STRUC Tss backlink DW ?,? esp0 DD ? ss0 DW ?,? esp1 DD ? ss1 DW ?,? esp2 DD ? ss2 DW ?,? cr3 DD ? eip DD ? eflags DD ? eax DD ? ecx DD ? edx DD ? ebx DD ? esp DD ? ebp DD ? esi DD ? edi DD ? es DW ?,? cs DW ?,? ss DW ?,? ds DW ?,? fs DW ?,? gs DW ?,? ldt DW ?,? trap DW ? iomapbase DW ? ENDS ; DPMI register structure STRUC Dpmi_regs LABEL edi DWORD di DW ? di_hi DW ? LABEL esi DWORD si DW ? si_hi DW ? LABEL ebp DWORD bp DW ? bp_hi DW ? res DD ? LABEL ebx DWORD LABEL bx WORD bl DB ? bh DB ? bx_hi DW ? LABEL edx DWORD LABEL dx WORD dl DB ? dh DB ? dx_hi DW ? LABEL ecx DWORD LABEL cx WORD cl DB ? ch DB ? cx_hi DW ? LABEL eax DWORD LABEL ax WORD al DB ? ah DB ? ax_hi DW ? flags DW ? es DW ? ds DW ? fs DW ? gs DW ? ip DW ? cs DW ? sp DW ? ss DW ? ENDS ; to access a descriptor entry more easily STRUC Descriptor limit0_15 DW ? base0_15 DW ? base16_23 DB ? LABEL types WORD types0 DB ? types1 DB ? base24_31 DB ? ENDS ; Almost the same as a descriptor, but its a gate STRUC Gate offset0 DW ? sel DW ? reserved DB ? gtype DB ? offset1 DW ? ENDS ; for DPMI call memory information STRUC Dpmi_meminfo available_memory DD ? available_pages DD ? available_lockable_pages DD ? linear_space DD ? unlocked_pages DD ? available_physical_pages DD ? total_physical_pages DD ? free_linear_space DD ? max_pages_in_paging_file DD ? reserved DD 3 DUP(?) ENDS ; also for easy access STRUC Farptr16 ; A 16 bit far ptr LABEL ptr DWORD offset DW ? sel DW ? ENDS STRUC Farptr32 ; A 32 Bit far ptr LABEL ptr FWORD offset DD ? sel DW ? pad DW ? ; one for align ENDS STRUC Temp ; for temporary variables LABEL d0 DWORD LABEL w0 WORD b0 DB ? b1 DB ? LABEL w1 WORD b2 DB ? b3 DB ? ENDS STRUC Callback DB 0Fh,0A8h ; PUSH gs DB 0Fh,0A0h ; PUSH fs DB 1Eh ; PUSH ds DB 06h ; PUSH es DB 9Ch ; PUSHF DB 66h,60h ; PUSHAD instruction DB 68h ; PUSH WORD instruction ds DW 0 ; immediate 0 used as free flag DB 66h,68h ; PUSH DWORD instruction esi DD 0 ; immediate data DB 0B9h ; MOV CX,? instruction es DW 0 ; immediate data DB 66h,68h ; PUSH DWORD instruction edi DD 0 ; immediate data DB 0EAh ; JMP FAR PTR ?:? intruction ptr Farptr16 ? ; immediate data ENDS ; The data structure for privat data STRUC Pdata rmstack DB RMSTACKLEN DUP(?) pmstack DB PMSTACKLEN DUP(?) vcpistack DB VCPISTACKLEN DUP(?) vcpitss Tss ? exceptiontasks Tss NUM_EXCEPTIONS DUP(?) exceptions Farptr32 32 DUP(?) lowint Farptr32 NUM_EXCEPTIONS DUP(?) DB 256 DUP(?) LABEL exceptionstack WORD idt Gate 256 DUP(?) gdt Descriptor GDT_NUM_ENTRIES DUP(?) LABEL after WORD ENDS ; if running under VCPI, this is (page aligned) followed by the ; pagedirectory and the pagetables. ; [fold] ] ;▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒ ; DATA ;▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒ SEGMENT _DATA PUBLIC USE16 'DATA' PUBLIC pm_exit ; user procedure at exit ; [fold] [ lvcpistruc DD ? ; VCPI switch structure linear address LABEL vcpi_switch_struct WORD vcpi_cr3 DD ? ; VCPI CR3 value for protected mode vcpi_gdtaddx DD ? ; linear addx of GDT limit and base vcpi_idtaddx DD ? ; linear addx of IDT limit and base vcpi_selldt DW 0 ; LDT selector for protected mode vcpi_seltss DW SELVCPITSS ; TSS selector for protected mode vcpi_eip DW off v_rmtopmswpm; destination EIP in protected mode DW 0 vcpi_cs DW SELCS ; destination CS in protected mode emspage DW -1 ; For some VCPI Managers picbasetab DB 88h,90h,98h,0A0h,0A8h,0B0h,0B8h,68h,78h,-1 initrouttbl DW r_init,x_init,v_init,d_init exitrouttbl DW r_exit,x_exit,v_exit ; exit functions. DPMI not needed pm_exit DW ret_only ; Just a ret int31functbl DW 0000h, 0001h, 0002h, 0003h, 0006h DW 0007h, 0008h, 0009h, 000ah, 000bh DW 000ch, 000eh, 000fh DW 0100h, 0101h, 0102h DW 0200h, 0201h, 0202h, 0203h DW 0204h, 0205h DW 0300h, 0301h, 0302h, 303h, 304h DW 0305h, 0306h DW 0400h DW 0500h, 0501h, 0502h, 0503h, 050ah DW 0600h, 0601h, 0602h, 0603h, 0604h DW 0702h, 0703h DW 0800h, 0801h DW 0900h, 0901h, 0902h IF PMODEDJ_EXT EQ 1 DW 0A00h ENDIF DW 0E00h, 0E01h INT31FUNCNUM = ($ - int31functbl) / 2 int31routtbl DW int310000, int310001, int310002, int310003, int310006 DW int310007, int310008, int310009, int31000a, int31000b DW int31000c, int31000e, int31000f DW int310100, int310101, int310102 DW int310200, int310201, int310202, int310203 DW int310204, int310205 DW int310300, int310301, int310302, int310303, int310304 DW int310305, int310306 DW int310400 int31mrouttbl DW int310500v,int310501v,int310502v,int310503v,int31050av DW int310600, int310601, int310602, int310603, int310604 DW int310702, int310703 int31phystbl DW int310800v,int310801v DW int310900, int310901, int310902 IF PMODEDJ_EXT EQ 1 DW int310a00 ENDIF DW int310e00, int310e01 int31mxrouttbl DW int310500x,int310501x,int310502x,int310503x,int31050ax int31mrrouttbl DW int310500r, int310501r, int310502r, int310503r DW int31050ar int31mnrouttbl DW int310500rnomem, int31fail8013, int31fail8023 DW int31fail8023, int31fail8023 int31physxrtbl DW int310800xr, int310801xr IF PMODEDJ_EXT EQ 1 apitab: APITAB_SIZE = $ - apitab pmodedj_id DB 'DJGPP',0 PMODEDJ_ID_SIZE = $ - pmodedj_id ENDIF ALIGN 4 ; Placed here, coz my TASM had problems putting this in the code common_callbacks Callback CALLBACKS DUP(<>) segmentbases DW 16*2 DUP(0) ; segment bases for function 0002h segmentbases_SIZE = ($ - segmentbases) rawextmemused DW 1 ; raw extended memory used in K rawextmembase DD 0ffffffffh ; raw extended memory base rawextmemtop DD 0 ; raw extended memory top rmidtlimit DW 3ffh ; real mode IDT limit rmidtbase DD 0 ; real mode IDT base ENDS SEGMENT _BSS PUBLIC USE16 'BSS' gdtlimit DW ? ; GDT limit gdtbase DD ? ; GDT base idtlimit DW ? ; IDT limit idtbase DD ? ; IDT base SetMasterPIC DW ? ; offset of PIC set routine ResetMasterPIC DW ? ; offset of PIC reset routine SetA20 DW ? ; offset of A20 set routine ResetA20 DW ? ; offset of A20 reset routine pmstackbase DD ? ; bottom of protected mode stack area pmstacktop DD ? ; top of protected mode stack area rmstackbase DW ? ; bottom of real mode stack area rmstacktop DW ? ; top of real mode stack area processortype DB ? ; processor type pmodetype DB ? ; protected mode type reprogrampic DB ? ; if first PIC should be reprogrammed from_us DB ? ; if int call by PMODE picslaveold DB ? ; old PIC slave base interrupt picmasterold DB ? ; old PIC master base interrupt picslavenew DB ? ; New PIC slave base picmasternew DB ? ; New PIC master base temp0 Temp ? ; temporary variables temp1 Temp ? ; " " olda20 DB ? detectionflags DB ? oldCR0L DB ? ; low byte of CR0 newEM_MP DB ? ; user specified EM and MP xms_call Farptr16 ? oldint15vector DD ? oldint2fvector DD ? pagedir DD ? ; linear address of pagedirectory pagetablebase DD ? ; base of page table area pagetabletop DD ? ; top of page table area pagetablefree DD ? ; base of available page table area pagetabledelta DD ? ; # of KB for allocates pagetables privatedataseg DW ? ; segment of privat data dpmiepmode Farptr16 ? ; DPMI protected mode entry vcpiswitchstack Farptr32 ? ; VCPI temporary mode switch stack vcpi_service Farptr32 ? ; VCPI code pointer rmtopmswrout DW ? ; offset of real to protected routine pmtormswrout DW ? ; offset of protected to real routine rmstackparmtop DW ? ; for functions 0300h, 0301h, 0302h DB 128 DUP(?) ; little stack at exit LABEL endstack WORD ENDS ; [fold] ] ;▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒ ; DETECT/INIT CODE ;▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒ SEGMENT _TEXT PUBLIC USE16 'CODE' PUBLIC pm_info ; procedure to get info PUBLIC pm_init ; switches to protected mode ;░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ ; [fold] [ ; pm_info: Get protected mode info ; In: ; AX = ; Bit 0 = 0: Check for DPMI first, else check for VCPI first ; Bit 1 : ignored and reserved for pm_init ; ; Bit 8 = 1: forbid raw ; Bit 9 = 1: forbid XMS ; Bit 10 = 1: forbid VCPI ; Bit 11 = 1: forbid DPMI ; ; Out: ; AX = return code: ; 0000h = successful ; 0001h = no 80386+ detected ; 0002h = system already in protected mode and no VCPI or DPMI found ; 0003h = no way to switch into protected mode ; CF = set on error, if no error: ; BX = number of paragraphs needed for protected mode data (may be 0) ; CL = processor type: ; 02h = 80286 ; 03h = 80386 ; 04h = 80486 ; 05h = 80586 ; 06h-FFh = reserved for future use ; CH = protected mode type: ; 00h = raw ; 01h = XMS ; 02h = VCPI ; 03h = DPMI ; ; Remark by MG: spaghetticode! ; ;░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ pm_info: push dx si di bp ds es bx cx ; preserve registers mov [detectionflags],ah ; store detection flags test al,1 ; check order of DPMI/VCPI detection jz short @@infof0 call @@detect_VCPI ; check for VCPI first call @@detect_DPMI ; check for DPMI second jmp short @@infof2 ; neither found, go on to XMS check @@infof0: call @@detect_DPMI ; check for DPMI first call @@detect_VCPI ; check for VCPI second ;----------------------------------------------------------------------------- @@infof2: smsw ax ; AX = machine status word test al,1 ; is system in protected mode? mov ax,2 ; error code in case protected mode jnz short @@infofail ; if in protected mode, fail mov ch,1 ; pmode type XMS test [detectionflags],2 ; XMS allowed? jnz short @@chkr mov ax,4300h ; check for XMS int 2fh cmp al,80h ; XMS present? jz short @@w1 ; if so, go on @@chkr: sub ch,ch ; set type to raw test [detectionflags],1 ; raw allowed? jz short @@w1 ; if so mov ax,3 ; else set error code jmp short @@infofail ; and fail @@w1: sub bx,bx ; no special memory needed ;----------------------------------------------------------------------------- @@infof1: add bx,(SIZE Pdata+15) / 16 ; Size of privatdata structure jmp short @@infook ; go to done ok ;----------------------------------------------------------------------------- @@infofail: pop cx bx ; restore BX and CX stc ; carry set, failed jmp short @@infodone ;----------------------------------------------------------------------------- @@infook: mov [pmodetype],ch ; store pmode type add sp,4 ; skip BX and CX on stack xor ax,ax ; success code, also clear carry flag clc ; Signal success ;----------------------------------------------------------------------------- @@infodone: pop es ds bp di si dx ; restore other registers ret ; return ;───────────────────────────────────────────────────────────────────────────── ; [fold] [ @@detect_DPMI: ; detect a DPMI host pop bp ; pop return address from stack test [detectionflags],8 ; DPMI allowed? jnz short @@detect_DPMIdone ; if not, quit sub ax,ax mov es,ax mov ax,[es:02Fh*4] or ax,[es:02Fh*4+2] ; check if multiplex set jz short @@detect_DPMIdone mov ax,1687h ; check for DPMI int 2fh or ax,ax ; DPMI present? jnz short @@detect_DPMIdone ; if no, exit routine mov ax,3 ; error code in case DPMI not 32bit test bl,1 ; is DPMI 32bit? jz short @@detect_DPMIdone ; if not, this DPMI host is no good mov ax,1 ; error code in case no processor 386+ cmp cl,3 ; is processor 386+? (redundant) jb short @@infofail ; if no, fail mov [dpmiepmode.offset],di ; store DPMI initial mode switch addx mov [dpmiepmode.sel],es mov bx,si ; BX = number of paragraphs needed mov ch,3 ; pmode type is 3 (DPMI) jmp @@infook ; go to done ok @@detect_DPMIdone: jmp bp ; return to calling routine ; [fold] ] ;───────────────────────────────────────────────────────────────────────────── ; [fold] [ @@detect_VCPI: ; detect a VCPI server pop bp ; pop return address from stack call @@detect_processor ; get processor type mov ax,1 ; error code in case no processor 386+ cmp cl,3 ; is processor 386+? jb short @@infofail ; if no, no VCPI mov [processortype],cl ; store processor type test [detectionflags],4 ; VCPI allowed? jnz @@detect_VCPIdone ; if not, ignore xor ax,ax ; get INT 67h vector mov es,ax mov ax,[es:67h*4] or ax,[es:67h*4+2] ; is vector NULL jz short @@detect_VCPIdone ; if yes, no VCPI cmp [emspage],-1 ; if already EMS Page allocated, jnz short @@no_alloc ; skip mov ah,40H ;Get Status int 67h cmp ah,0 jne short @@no_alloc ;maybe only EMS turned off mov ah,42H ;Get Unallocate Page Count int 67h cmp ah,0 jne short @@no_alloc cmp bx,dx ;Other Program EMS Page Used? jne short @@no_alloc ;Used!! mov bx,1 mov ah,43H ;Allocate Pages(1 Page Only), int 67h ;so EMS has to be turned on cmp ah,0 jne short @@no_alloc ;if page alloc failed mov [emspage],dx ; store EMS page @@no_alloc: mov ax,0de00h ; call VCPI installation check int 67h or ah,ah ; AH returned as 0? jnz short @@detect_VCPIdone2 ; if no, no VCPI ; determine here # of max pagetables! + pagedir mov ax,0DE03h ; # of free pages int 67h add edx,1023+1024+2048 ; align to next pagetable + and dx,NOT 1023 ; first MB + 8 MB extra linear shl edx,2 ; # of bytes for page tables mov [pagetabledelta],edx ; store size of pagetables shr edx,12-8 ; calc # of paragraphs mov bx,dx ; if highword is not zero, you would ; still have enough mem! add bx,(4096+4096) / 16 ; page directory and page align mov ch,2 ; pmode type is 2 (VCPI) jmp @@infof1 ; go to figure other memory needed @@detect_VCPIdone2: mov dx,[emspage] cmp dx,-1 jz short @@detect_VCPIdone ; free allocated EMS page mov ah,45h int 67h mov [emspage],-1 ; reset to 'no emspage allocated' @@detect_VCPIdone: jmp bp ; return to calling routine ; [fold] ] ;───────────────────────────────────────────────────────────────────────────── ; [fold] [ @@detect_processor: ; get processor: 286, 386, 486, or 586 xor cl,cl ; processor type 0 in case of exit pushf ; transfer FLAGS to BX pop bx mov ax,bx ; try to clear high 4 bits of FLAGS and ah,0fh push ax ; transfer AX to FLAGS popf pushf ; transfer FLAGS back to AX pop ax and ah,0f0h ; isolate high 4 bits cmp ah,0f0h je short @@detect_processordone ; if bits are set, CPU is 8086/8 mov cl,2 ; processor type 2 in case of exit or bh,0f0h ; try to set high 4 bits of FLAGS push bx ; transfer BX to FLAGS popf pushf ; transfer FLAGS to AX pop ax and ah,0f0h ; isolate high 4 bits jz short @@detect_processordone ; if bits are not set, CPU is 80286 inc cx ; processor type 3 in case of exit push eax ebx edx ; preserve 32bit registers pushfd ; transfer EFLAGS to EBX pop ebx mov eax,ebx ; try to flip AC bit in EFLAGS xor eax,40000h push eax ; transfer EAX to EFLAGS popfd pushfd ; transfer EFLAGS back to EAX pop eax xor eax,ebx ; AC bit fliped? jz short @@detect_try_cpuid ; if no, CPU is 386 inc cx ; processor type 4 in case of exit @@detect_try_cpuid: mov eax,ebx ; try to flip ID bit in EFLAGS xor eax,200000h push eax ; transfer EAX to EFLAGS popfd pushfd ; transfer EFLAGS back to EAX pop eax xor eax,ebx ; ID bit fliped? jz short @@detect_processordone2; if no, return 386 or 486 ; Use cpuid instruction if supported ; cpuid is supported on some new 486, some new Nx586, Pentium, Am5x86, ; Cyrix 6x86 and all newer processors. I'm not sure about Cyrix 5x86. ; Nx586 returns 5, Am5x86 returns 4, Cyrix 6x86 returns 6. mov eax,0 ; check if CPUID accepts 1 in eax db 0fh,0a2h ; CPUID or eax,eax ; eax for distant future compatibility mov cx,5 ; processor type 5 in case of exit jz short @@detect_processordone2; cpuid can not be used further mov eax,1 ; get chip type and supported features db 0fh,0a2h ; CPUID and ah,0fh ; clear type field movzx cx,ah ; return family field. @@detect_processordone2: pop edx ebx eax ; restore 32bit registers @@detect_processordone: ret ; return ; [fold] ] ; [fold] ] ;░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ ; [fold] [ ; pm_init: switch into protected mode ; In: ; AX = Bit 0 = 1 Check for VCPI first ; Bit 1 = 1 Reprogram first PIC if possible ; Bit 8 = 1 forbid raw ; Bit 9 = 1 forbid XMS ; Bit 10 = 1 forbid VCPI ; Bit 11 = 1 forbid DPMI ; ES = real mode segment for protected mode data (ignored if not needed) ; Out: ; AX = return code: ; 0000h = successful ; 0001h = no 80386+ detected ; 0002h = system already in protected mode and no VCPI or DPMI found ; 0003h = (changed) no way to switch into protected mode ; 0004h = could not enable A20 gate ; 0005h = DPMI - could not enter 32bit protected mode ; CF = set on error, if no error running in protected mode: ; ESP = high word clear ; CS = 16bit selector for real mode CS with limit of 64k ; SS = selector for real mode SS with limit of 64k ; DS = selector for real mode DS with limit of 64k ; ES = selector for PSP with limit of 100h ; FS = 0 (NULL selector) ; GS = 0 (NULL selector) ; Rem: DS == SS, if DS == SS on entry ;░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ ; [fold] [ pm_init: push ax call pm_info pop ax jnc short @@initf0 ; error? ret ; yup, abort @@initf0: ; no error, init protected mode test ax,2 setnz [reprogrampic] push esi edi ebp cld setmemw es,<off 0+Pdata.gdt>,<GDT_NUM_ENTRIES * SIZE Descriptor> ; clear GDT with all 0 mov [privatedataseg],es ; save data segment movzx bx,[pmodetype] ; jump to appropriate init code shl bx,1 jmp [bx + initrouttbl] ; [fold] ] ;═════════════════════════════════════════════════════════════════════════════ ; [fold] [ d_init: ; DPMI protected mode init mov ax,1 ; enter DPMI protected mode call [dpmiepmode.ptr] sub bx,bx jnc short init_done ; error? if not, finished here mov bx,5 ; error entering protected mode, set ;----------------------------------------------------------------------------- init_done: ; return with return code mov ax,bx pop ebp edi esi ret ; [fold] ] ;───────────────────────────────────────────────────────────────────────────── ; This assumes, that the extender runs in 1 Code and 1 Datasegment. ; (This applies for model tiny, small, compact, and sometimes for tpascal) ; The original source put here created a codesegment descriptor ; to return from this procedure. But as pm_init is near-called, there is no ; need for such a code. ; [fold] [ dvxr_init: ; DPMI/VCPI/XMS/raw common init tail sub bx,bx ; error code = 0 (no error) mov fs,bx ; changed, when switching by raw mov gs,bx clc ; signal success jmp init_done ; [fold] ] ;═════════════════════════════════════════════════════════════════════════════ ; In: ES = segment for host private data buffer ; [fold] [ v_init: ; VCPI protected mode init mov [SetMasterPIC],off v_setpic mov [ResetMasterPIC],off v_resetpic mov [SetA20],off v_seta20 mov [ResetA20],off v_reseta20 mov ax,0de0ah ; get PIC mappings int 67h mov [picmasterold],bl mov [picslaveold],cl mov ax,0de07h ; get CR0 int 67h mov [oldCR0L],bl ; save old state sar bl,1 and bl,3 ; keep EM and MP mov [newEM_MP],bl ptr2lin es,<off 0+Pdata.after>,ax,bx,eax,ebx add eax,4095 and ax,NOT 4095 ; align data area on page mov [pagedir],eax ; store add eax,1000h ; skip pagedir mov [pagetablebase],eax ; set base of page table area add eax,[pagetabledelta] ; size of pagetables mov [pagetabletop],eax ; set top of page table area lin2seg es,[pagedir],eax,ax mov gs,ax ; GS = segment of page directory mov es,ax ; ES = segment of page directory add ax,100h mov fs,ax ; FS = segment of first page table setmemw es,0,2*4096 ; clear page dir and first page table copy es,fs,ax ; ES = segment of first pagetable push ds mov ds,[privatedataseg] mov si,off SELVCPI+Pdata.gdt ; descriptors for VCPI host xor di,di ; get VCPI protected mode interface mov ax,0de01h int 67h pop ds ; restore old ds movzx eax,di ; set base of usable page table area add ax,4095 and ax,NOT 4095 ; align to next pagetable add eax,[pagetablebase] mov [pagetablefree],eax mov [vcpi_service.sel],SELVCPI ; store protected mode VCPI call CS mov [vcpi_service.offset],ebx ; store protected mode VCPI call EIP ; For safety clear reserved bits 9-11 @@v_initl0: and [byte ptr es:di+1],0f1h sub di,4 jnc @@v_initl0 ; --------- Link pagetables in pagedirectory ---------- mov si,es ; DX = current page table segment xor ebx,ebx ; index in page dir, also loop counter mov ebp,[pagetabledelta] shr ebp,12 ; # of pagetables jmp short @@v_initl1f0 @@v_initl1: xor di,di ; clear page table mov cx,800h xor ax,ax rep stosw nop ; 386 bug @@v_initl1f0: mov cx,si shr cx,8 ; get page number mov ax,0de06h ; get physical address int 67h and dh,0f1h ; For safety clear reserved bits 9-11 or dl,7 ; set present, User and R/W bit mov [gs:ebx*4],edx ; store in page directory add si,100h ; increment page table segment mov es,si inc bx ; increment index in page directory cmp bx,bp ; at end of page tables? jb @@v_initl1 ; if no, loop ;----------------------------------------------------------------------------- mov ecx,[pagedir] shr ecx,12 mov ax,0de06h int 67h ; get physical address mov [vcpi_cr3],edx ptr2lin ds,<off gdtlimit>,ax,bx,eax,ebx mov [vcpi_gdtaddx],eax ptr2lin ds,<off idtlimit>,ax,bx,eax,ebx mov [vcpi_idtaddx],eax ptr2lin ds,<off vcpi_switch_struct>,ax,bx,eax,ebx mov [lvcpistruc],eax mov [rmtopmswrout],off v_rmtopmsw mov [pmtormswrout],off v_pmtormsw ; [fold] ] ;───────────────────────────────────────────────────────────────────────────── ; [fold] [ vxr_init: ; VCPI/XMS/raw common init tail mov [from_us],0 ; init mov pdseg,[privatedataseg] ; access private data sub edx,edx mov dx,off critical_error ; Standard exception handler mov si,off 0 + Pdata.exceptions mov ax,NUM_EXCEPTIONS @@lp: mov [pdseg:si + Farptr32.sel],SELCS mov [pdseg:si + Farptr32.offset],edx mov [pdseg:si + Farptr32.pad],0 add si,SIZE Farptr32 dec ax jnz @@lp DB 66h ; NMI is passed down to real mode mov ax,off NMI_exception DW 0 mov [pdseg:off (2*SIZE Farptr32) + Pdata.exceptions],eax IF FAST_FPU_EMU EQ 1 mov ax,[pdseg:7*SIZE Farptr32 + Pdata.exceptions.sel] mov [cs:FPU_emu_vector.sel],ax mov eax,[pdseg:7*SIZE Farptr32 + Pdata.exceptions.offset] mov [cs:FPU_emu_vector.offset],eax ENDIF copy [picslavenew],[picslaveold],al copy [picmasternew],[picmasterold],al test [reprogrampic],-1 ; reprogram first PIC? jz short @@pice cmp [picmasternew],8 ; default value for first PIC? jnz short @@pice ; if not, keep hands off! @@gopic:mov di,off picbasetab copy es,0,ax ; ES -> Base of IVT jmp short @@lpde @@lpd: mov eax,[es:edx*4] ; get first interrupt vector mov cl,7 @@lpc: inc dx cmp eax,[es:edx*4] ; contest the same? jnz short @@lpde ; if not, try next dec cl ; Rem: This is faster than 'loop'! jnz @@lpc ; Compare next sub dx,7 ; yeah, found a place jmp short @@repr @@lpde: movzx edx,[BYTE PTR di] inc di cmp dl,-1 jnz @@lpd @@repr: cmp dl,-1 ; search successful? jz short @@pice ; if not, everything's the same mov [picmasternew],dl call [SetMasterPIC] ; else set new pic base @@pice: ptr2lin pdseg,<off 0+Pdata.idt>,ax,bx,eax,ebx mov [idtbase],eax ; set IDT base address mov [idtlimit],(256 * SIZE Gate)-1 mov [rmstackbase],off 0+Pdata.rmstack ; set top and base of mov [rmstacktop],off RMSTACKLEN + Pdata.rmstack ; real mode stack ; ------------------ Set up IDT ----------------- sub di,di mov si,off common_int_handler sub cx,cx @@vxr_idt_loop1: mov [pdseg:di + Pdata.idt.offset0],si mov [pdseg:di + Pdata.idt.offset1],0 mov [pdseg:di + Pdata.idt.reserved],0 mov [pdseg:di + Pdata.idt.sel],SELCS mov [pdseg:di + Pdata.idt.gtype],8Fh ; trap gate add di,SIZE Gate add si,INT_HANDLER_SIZE inc cx cmp cx,256 jne @@vxr_idt_loop1 ; --------------- Set up hardware IRQ handlers -------------- mov cl,8 mov bx,off common_hardirq_handler movzx dx,[picmasterold] shl dx,2 ; rm offset in IVT movzx di,[picmasternew] shl di,3 ; offset in IDT @@hi1: mov [cs:bx+2],dx ; store rm offset mov [pdseg:di + Pdata.idt.offset0],bx mov [pdseg:di + Pdata.idt.gtype],8Eh ; interrupt gate add di,SIZE Gate add bx,HARDIRQ_HANDLER_SIZE add dx,4 dec cl jne @@hi1 mov cl,8 movzx dx,[picslaveold] shl dx,2 ; rm offset in IVT movzx di,[picslavenew] shl di,3 ; offset in IDT @@hi2: mov [cs:bx+2],dx ; store rm offset mov [pdseg:di + Pdata.idt.offset0],bx mov [pdseg:di + Pdata.idt.gtype],8Eh ; interrupt gate add di,SIZE Gate add bx,HARDIRQ_HANDLER_SIZE add dx,4 dec cl jne @@hi2 ; --------------- Set up exception handler tasks ------------ sub di,di mov si,SELTASKS sub cx,cx mov bx,off 0 + Pdata.lowint @@vxr_idt_loop2: mov ax,[pdseg:di + Pdata.idt.offset1] shl eax,16 mov ax,[pdseg:di + Pdata.idt.offset0] mov [pdseg:bx + Farptr32.offset],eax mov ax,[pdseg:di + Pdata.idt.sel] mov [pdseg:bx + Farptr32.sel],ax mov [pdseg:bx + Farptr32.pad],0 mov [pdseg:di + Pdata.idt.offset0],0 mov [pdseg:di + Pdata.idt.offset1],0 mov [pdseg:di + Pdata.idt.reserved],0 mov [pdseg:di + Pdata.idt.sel],si mov [pdseg:di + Pdata.idt.gtype],85h ; set to Task Gate add di,SIZE Gate add si,SIZE Descriptor add bx,SIZE Farptr32 inc cx cmp cx,NUM_EXCEPTIONS jne @@vxr_idt_loop2 IF FAST_FPU_EMU EQ 1 ; 'FPU not present' called by trap gate DB 66h mov [WORD PTR pdseg:(7*SIZE Gate) + Pdata.idt.offset0],off FPU_emulation DW 0 mov [pdseg:(7*SIZE Gate) + Pdata.idt.reserved],0 mov [pdseg:(7*SIZE Gate) + Pdata.idt.sel],SELCS mov [pdseg:(7*SIZE Gate) + Pdata.idt.gtype],8Fh ENDIF ; Set up special ints mov [pdseg:8*31h+Pdata.idt.offset0],off int31 ; protected mode INT 31h mov [pdseg:8*21h+Pdata.idt.offset0],off int21 ; protected mode INT 21h mov [pdseg:8*23h+Pdata.idt.offset0],off int23pm ; pm INT 23h mov [pdseg:8*24h+Pdata.idt.offset0],off int24pm ; pm INT 24h mov [pdseg:8*2fh+Pdata.idt.offset0],off int2fpm ; pm INT 2fh ;----------------------------------------------------------------------------- ptr2lin pdseg,<off 0+Pdata.pmstack>,ax,bx,eax,ebx mov [pmstackbase],eax ptr2lin pdseg,<off PMSTACKLEN + Pdata.pmstack>,ax,bx,eax,ebx mov [pmstacktop],eax ;----------------------------------------------------------------------------- ptr2lin pdseg,<off 0 + Pdata.gdt>,ax,bx,eax,ebx mov [gdtbase],eax ; set GDT base address mov [gdtlimit],(GDT_NUM_ENTRIES * SIZE Descriptor) - 1 ;----------------------------------------------------------------------------- ptr2lin pdseg,<off 0 + Pdata.vcpitss>,ax,bx,eax,ebx mov [pdseg:SELVCPITSS + Pdata.gdt.base0_15],ax shr eax,16 mov [pdseg:SELVCPITSS + Pdata.gdt.base16_23],al mov [pdseg:SELVCPITSS + Pdata.gdt.base24_31],ah mov [pdseg:SELVCPITSS + Pdata.gdt.limit0_15],SIZE Tss-1 mov [pdseg:SELVCPITSS + Pdata.gdt.types],0089h mov [vcpiswitchstack.offset],off VCPISTACKLEN+Pdata.vcpistack mov [vcpiswitchstack.sel],SELPRIVAT ;----------------------------------------------------------------------------- setmemw [privatedataseg],<off 0+Pdata.vcpitss>,<SIZE Tss> ; clear Switch TSS mov es,[privatedataseg] mov eax,[vcpi_cr3] ; set CR3 in TSS mov [es:Pdata.vcpitss.cr3],eax mov [es:Pdata.vcpitss.iomapbase],SIZE Tss ;----------------------------------------------------------------------------- mov [WORD PTR pdseg:-2+Pdata.exceptionstack],0 mov di,off 0 + Pdata.exceptiontasks ; set up exception tasks sub esi,esi mov si,off common_exception_without_error_handler mov edx,[vcpi_cr3] ; EDX = page directory sub ecx,ecx @@exceptiontaskloop: push cx di setmemw pdseg,di,<SIZE Tss> ; Clear exception task pop di cx mov [pdseg:di + Tss.ss0],SELPRIVAT mov [pdseg:di + Tss.esp0],off 0+Pdata.exceptionstack mov [pdseg:di + Tss.ss1],SELPRIVAT mov [pdseg:di + Tss.esp1],off 0+Pdata.exceptionstack mov [pdseg:di + Tss.ss2],SELPRIVAT mov [pdseg:di + Tss.esp2],off 0+Pdata.exceptionstack mov [pdseg:di + Tss.ss],SELPRIVAT mov [pdseg:di + Tss.esp],off 0+Pdata.exceptionstack mov [pdseg:di + Tss.cs],SELCS mov [pdseg:di + Tss.eip],esi mov [pdseg:di + Tss.ds],SELPRIVAT ; es and ds are needed mov [pdseg:di + Tss.es],SELDS mov [pdseg:di + Tss.eflags],0 mov [pdseg:di + Tss.cr3],edx mov [pdseg:di + Tss.iomapbase],SIZE Tss mov [pdseg:di + Tss.ebx],ecx ; store exception number push cx and cl,7 mov ah,1 shl ah,cl ; ah is mask for pic pop cx mov al,cl ; al is high 5 bits of cx used and al,0f8h ; to compare to pic base mov [pdseg:di + Tss.eax],eax mov [pdseg:di + Tss.edx],off 0 + Pdata.exceptionstack cmp al,8 ; exceptions 8, 9-0eh have error jne short @@go_on ; and we can skip the checking cmp cl,9 je short @@go_on cmp cl,0fh je short @@go_on sub eax,eax mov ax,off common_exception_with_error_handler mov [pdseg:di + Tss.eip],eax @@go_on: mov [pdseg:di + Tss.ecx],0 ; to be used as default error code add di,SIZE Tss inc cx cmp cx,NUM_EXCEPTIONS jne @@exceptiontaskloop ;----------------------------------------------------------------------------- ptr2lin pdseg,<off 0+Pdata.exceptiontasks>,ax,bx,eax,ebx mov bx,SELTASKS mov ecx,SIZE Tss-1 ; Limit mov dx,1089h ; waiting Task sub si,si @@taskgateloop: push eax dx mov [pdseg:bx + Pdata.gdt.limit0_15],cx ; limit = CX mov [pdseg:bx + Pdata.gdt.base0_15],ax shr eax,16 mov [pdseg:bx + Pdata.gdt.base16_23],al mov [pdseg:bx + Pdata.gdt.base24_31],ah mov eax,ecx shr eax,8 and dh,0F0h ; Clear limit16_19 or dh,ah ; Set it mov [pdseg:bx + Pdata.gdt.types],dx ; access rights = DX add bx,8 pop dx eax add eax,SIZE Tss inc si cmp si,NUM_EXCEPTIONS jne @@taskgateloop ;----------------------------------------------------------------------------- init_dsc 0,SELCORE,0FFFFFh,0D092h init_dsc cs,SELCS,0FFFFh,109Ah ; Make selector for CS init_dsc 0,SELREAL,ecx,1092h ; set real mode attributes descriptor init_dsc cs,SELALIASCS,ecx,5092h; To write to CS in protected mode init_dsc ds,SELDS,ecx,dx ; Make selector for DS init_dsc ax,SELINT24,ecx,dx ; Make selector for INT 24 callback init_dsc pdseg,SELPRIVAT,<SIZE Pdata>,dx mov bx,SIZE Descriptor*SYSSELECTORS ; BX = base of free descriptors push bx ; store CS selector init_dsc cs,bx,0FFFFh,109Ah ; make caller cs selector push bx bx ; store SS and DS selectors init_dsc ss,bx,ecx,5092h ; set caller SS descriptor mov ax,ds mov si,ss ; SS = DS? cmp ax,si jz short @@skip ; if so, they have to be equal! pop ax ; else set new selector for DS push bx init_dsc ds,bx,ecx,dx @@skip: push bx ; get PSP segment mov ah,51h int 21h mov es,bx ; set caller environment descriptor mov si,bx pop bx mov ax,[es:2ch] or ax,ax ; is environment seg 0? jz short @@vxr_initf0 ; if yes, dont convert to descriptor mov [es:2ch],bx ; store selector value in PSP init_dsc ax,bx,ecx,dx @@vxr_initf0: init_dsc si,bx,0FFh,dx ; set caller PSP descriptor ;----------------------------------------------------------------------------- lea ecx,[ebx-8] ; CX = ES descriptor, just set pop ax ; AX = DS descriptor, from datasegment pop dx ; DX = SS descriptor, from stack pop si ; target CS, from codesegment mov di,off @@vxr_initf2 ; target EIP movzx ebx,sp ; EBX = SP, current SP - same stack movzx edi,di jmp [rmtopmswrout] ; jump to mode switch routine @@vxr_initf2: copy coreseg,SELCORE,ax copy pdseg,SELDS,ax mov eax,[coreseg:4*2Fh] ; check if multiplex set mov [pdseg:oldint2fvector],eax or eax,eax jnz short @@ok DB 66h mov [WORD PTR coreseg:4*2Fh],off int2frm ; set multiplex DW _TEXT @@ok: DB 66h mov [WORD PTR coreseg:4*23h],off int23rm ; set new INT 23h handler DW _TEXT DB 66h mov [WORD PTR coreseg:4*24h],off int24rm ; set new INT 24h handler DW _TEXT push ds copy ds,SELALIASCS,ax mov bx,off oldint21vector ; setting direct makes tlink puke mov eax,[coreseg:4*21h] ; get DOS vector mov [ds:bx],eax ; save pop ds DB 66h mov [WORD PTR coreseg:4*21h],off dos21rm ; set new DOS vector DW _TEXT mov eax,[coreseg:4*15h] ; get INT 15h vector mov [pdseg:oldint15vector],eax ; store INT 15h vector mov esi,[pdseg:rawextmembase] ; ESI = raw base of extended memory cmp esi,[pdseg:rawextmemtop] ; is there any raw extended memory? jae dvxr_init ; if no, go DPMI/VCPI/XMS/raw init DB 66h mov [WORD PTR coreseg:4*15h],off int15 ; MOV [4*15],_TEXT:offset int15 DW _TEXT ; set new INT 15h handler mov edi,[pdseg:rawextmemtop] ; EDI = raw top of extended memory mov eax,edi ; EAX = size of extended memory sub eax,esi sub eax,10h ; subtract memory control block size mov [coreseg:edi-16],eax ; store size in memory control block xor eax,eax mov [coreseg:edi-12],eax ; no next memory control block mov [coreseg:edi-8],eax ; no previous memory control block mov [coreseg:edi-4],al ; memory block is free jmp dvxr_init ; go to DPMI/VCPI/XMS/raw init tail ;───────────────────────────────────────────────────────────────────────────── ; set descriptor for VCPI/XMS/raw init ; In ; ax = real mode segment ; bx = Selector ; ecx = limit ; dx = access rights/type ; pdseg = segment to privat data ; Out ; bx+8, trashes eax vxr_initsetdsc: push dx movzx eax,ax ; EAX = base of segment shl eax,4 mov [pdseg:bx + Pdata.gdt.limit0_15],cx ; limit = CX mov [pdseg:bx + Pdata.gdt.base0_15],ax shr eax,16 mov [pdseg:bx + Pdata.gdt.base16_23],al mov [pdseg:bx + Pdata.gdt.base24_31],ah mov eax,ecx shr eax,8 and dh,0F0h ; Clear limit16_19 or dh,ah ; Set it mov [pdseg:bx + Pdata.gdt.types],dx ; access rights = DX add bx,8 pop dx ret ; [fold] ] ;═════════════════════════════════════════════════════════════════════════════ ; [fold] [ x_init: ; XMS protected mode init push es ; preserve ES, INT 2Fh destroys it mov ax,4310h ; get XMS driver address int 2fh mov [xms_call.offset],bx ; store XMS driver address mov [xms_call.sel],es pop es ; restore ES (buffer segment) call x_seta20 ; enable A20 mov bx,4 ; error code 0004h in case of error cmp ax,1 ; error enabling A20? jc init_done ; if yes, exit with error 0004h mov [SetA20],off x_seta20 ; procedure to enable a20 under XMS mov [ResetA20],off x_reseta20 ; resets a20 to startup state mov si,off int31mxrouttbl ; set XMS memory allocation functions ; [fold] ] ;───────────────────────────────────────────────────────────────────────────── ; [fold] [ xr_init: ; XMS/raw common init tail push es ; preserve ES push ds ; ES = DS for table copy pop es mov di,off int31mrouttbl mov cx,5 memcpyw ds,si,es,di,cx ; copy memory allocation function mov eax,[dword ptr int31physxrtbl] ; copy physical mapping functions mov [dword ptr int31phystbl],eax pop es ; restore ES (buffer segment) mov [rmtopmswrout],off xr_rmtopmsw ; set XMS/raw mode switch addresses mov [pmtormswrout],off xr_pmtormsw mov [SetMasterPIC],off xr_setpic ; set XMS/raw PIC program address mov [ResetMasterPIC],off xr_resetpic mov [picmasterold],8 ; assuming standard PIC mappings mov [picslaveold],70h mov ebx,cr0 ; get CR0 mov [oldCR0L],bl ; save old state sar bl,1 and bl,3 mov [newEM_MP],bl jmp vxr_init ; go to VCPI/XMS/raw continue init ; [fold] ] ;═════════════════════════════════════════════════════════════════════════════ ; [fold] [ r_init: ; raw protected mode init mov [SetA20],off r_seta20 ; procedure to enable a20 under raw mov [ResetA20],off r_reseta20 ; resets a20 to startup state mov ah,88h ; how much extended memory free int 15h mov si,off int31mnrouttbl ; SI -> no memory allocation functions or ax,ax ; if none, done with raw init jz xr_init movzx eax,ax ; convert AX K to ptr to top of mem shl eax,10 add eax,100000h mov [rawextmemtop],eax call r_seta20 ; enable A20 mov bx,4 jc init_done push es ; preserve ES (buffer segment) xor cx,cx ; ES -> 0 (interrupt vector table) mov es,cx les bx,[dword ptr es:4*19h] ; ES:BX -> int vector table mov eax,100000h ; initial free extended memory base cmp [dword ptr es:bx+12h],'SIDV'; VDISK memory allocation? jne short @@r_initf0 ; if present, get base of free mem mov eax,[dword ptr es:bx+2ch] ; get first free byte of extended mem add eax,0fh ; align on paragraph and eax,0fffff0h ; address is only 24bit @@r_initf0: dec cx ; ES -> 0ffffh for ext mem addressing mov es,cx cmp [dword ptr es:13h],'SIDV' ; VDISK memory allocation? jne short @@r_initf1 ; if present, get base of free mem movzx ebx,[word ptr es:2eh] ; get first free K of extended memory shl ebx,10 ; adjust K to bytes cmp eax,ebx ; pick larger of 2 addresses ja short @@r_initf1 mov eax,ebx @@r_initf1: pop es ; restore ES (buffer segment) mov si,off int31mnrouttbl ; SI -> no memory allocation functions cmp eax,[rawextmemtop] ; any valid free extended memory jae xr_init ; if none, done with raw init mov [rawextmembase],eax mov si,off int31mrrouttbl ; set raw memory allocation functions jmp xr_init ; go to XMS/raw continue init ; [fold] ] ; [fold] ] ;▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒ ; PROTECTED MODE KERNEL CODE ;▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒ ; [fold] [ ;═════════════════════════════════════════════════════════════════════════════ ; [fold] [ ; VCPI real to protected switch v_rmtopmsw: pushf ; store FLAGS cli push DGROUP pop ds pop [temp0.w0] ; move FLAGS from stack to temp mov [temp0.w1],ax ; store AX (protected mode DS) mov [temp1.w0],si ; store SI (protected mode CS) mov esi,[lvcpistruc] ; ESI = linear addx of VCPI structure mov ax,0de0ch ; VCPI switch to protected mode int 67h v_rmtopmswpm: mov ax,SELDS mov ds,ax mov es,cx ; load protected mode es xor eax,eax mov fs,ax ; load protected mode FS with NULL mov gs,ax ; load protected mode GS with NULL mov ax,[temp0.w0] and ax,0bfffh ; clear NT flag push eax popfd mov ss,dx ; load protected mode SS:ESP mov esp,ebx push [temp1.d0] ; push cs push edi ; push eip mov ds,[temp0.w1] ; caller ds DB 66h retf ; go to target addx in protected mode ; [fold] ] ;═════════════════════════════════════════════════════════════════════════════ ; [fold] [ ; VCPI protected to real switch v_pmtormsw: pushf ; store FLAGS cli push SELDS pop ds pop [temp0.w0] ; store flags mov [temp1.w0],ax ; save AX (real mode DS) lss esp,[vcpiswitchstack.ptr] ; set up switchstack sub ax,ax push eax ; real mode GS push eax ; real mode FS push [temp1.d0] ; real mode DS push ecx ; real mode ES push edx ; real mode SS push 0 bx ; real mode ESP push eax ; reserved DB 66h push _TEXT ; push dword _TEXT DW 0 ; real mode entry CS mov ax,_TEXT DB 66h push off @@v_pmtormswf0 ; push dword value DW 0 ; real mode entry IP copy ds,SELCORE,ax ; linear mem selector copy es,SELDS,ax ; data selector mov ax,0de0ch ; VCPI switch to real mode (V86) call [es:vcpi_service.ptr] @@v_pmtormswf0: push [temp0.w0] ; store old FLAGS push si ; store target CS in real mode push di ; store target IP in real mode iret ; go to target addx in real mode ; [fold] ] ;═════════════════════════════════════════════════════════════════════════════ ; [fold] [ ; XMS/raw real to protected switch xr_rmtopmsw: push DGROUP pop ds pushfd ; store EFLAGS cli push [vcpi_seltss] push si ; save SI lidt [fword ptr idtlimit] ; load protected mode IDT lgdt [fword ptr gdtlimit] ; load protected mode GDT mov si,[vcpi_seltss] mov ds,[privatedataseg] mov [ds:si + Pdata.gdt.types],0089h ; Clear busy bit mov esi,cr0 ; switch to protected mode or si,1 mov cr0,esi db 0eah ; JMP FAR PTR SELCODE:$+4 dw $+4,SELCS ; (clear prefetch que) pop si mov ds,ax ; load protected mode DS mov es,cx ; load protected mode ES xor ax,ax mov fs,ax ; load protected mode FS with NULL mov gs,ax ; load protected mode GS with NULL lldt ax ; load protected mode LDT pop ax ; set up task register ltr ax ; load protected mode TR clts ; free coprocessor pop eax mov ss,dx ; load protected mode SS:ESP mov esp,ebx and ah,0bfh ; set NT=0 in old EFLAGS push eax ; set current EFLAGS popfd push esi ; store protected mode target CS push edi ; store protected mode target EIP DB 66h retf ; go to targed addx in protected mode ; [fold] ] ;═════════════════════════════════════════════════════════════════════════════ ; [fold] [ ; XMS/raw protected to real switch xr_pmtormsw: push SELDS pop ds pushf ; store FLAGS cli push ax ; store AX (real mode DS) pop [temp0.w0] ; move real mode DS from stack to temp pop [temp0.w1] ; move FLAGS from stack to temp lidt [fword ptr rmidtlimit] ; load real mode IDT mov ax,SELREAL ; load descriptors with real mode seg mov ds,ax ; attributes mov es,ax mov fs,ax mov gs,ax mov ss,ax ; load descriptor with real mode attr movzx esp,bx ; load real mode SP, high word 0 mov eax,cr0 ; switch to real mode and al,0feh mov cr0,eax db 0eah ; JMP FAR PTR PMODE_TEXT:$+4 dw $+4,_TEXT ; (clear prefetch que) mov ss,dx ; load real mode SS mov es,cx ; load real mode ES xor ax,ax mov fs,ax ; load real mode FS with NULL mov gs,ax ; load real mode GS with NULL copy ds,DGROUP,ax ; datasegment push [temp0.w1] ; store old FLAGS mov ds,[temp0.w0] ; load real mode DS push si ; store real mode target CS push di ; store real mode target IP iret ; go to target addx in real mode ; [fold] ] ;═════════════════════════════════════════════════════════════════════════════ ; [fold] [ ; General interrupt handler common_int_handler: count = 0 REPT 256 DB 68h DW count*4 ; push rm IVT offet DB 0E9h DW @@int_handler - 2 - $ ; jump @@int_handler count = count +1 ENDM INT_HANDLER_SIZE = ($ - common_int_handler) / 256 @@int_handler: push 0 ds es fs gs pushad ; store general registers pushf and [WORD PTR esp],NOT 300h ; Clear IF and TF popf copy ds,SELDS,ax copy pdseg,SELPRIVAT,ax mov dx,[rmstacktop] movzx ebx,dx sub dx,RMONESTACKLEN cmp dx,[rmstackbase] ; exceeded real mode stack space? jb critical_error ; if yes, critical error (hang) mov [rmstacktop],dx ; update for possible reentrancy movzx esi,[word ptr esp+42] ; get intvector offset copy coreseg,SELCORE,ax sub bx,50 ; space on real mode stack mov ax,[esp+50] ; get flags and ax,NOT 300h ; Clear IF and TF (like in real mode) mov [pdseg:bx+32],ax ; put FLAGS mov [pdseg:bx+42],ax copy [pdseg:bx+34],[coreseg:esi],eax mov [word ptr pdseg:bx+38],off @@inte mov [word ptr pdseg:bx+40],_TEXT mov [pdseg:bx+44],esp ; protected mode stack mov [pdseg:bx+48],ss ; to return to protected mode dmemcpyw ss,esp,pdseg,ebx,32 ; copy to real mode stack mov dx,[privatedataseg] mov si,_TEXT mov di,off @@intrirqf0 jmp [pmtormswrout] ; switch to real mode @@intrirqf0: popad ; get general registers popf retf ; jump into rm int @@inte: pushf pushad ; store general registers copy ds,DGROUP,ax mov bp,sp mov dx,[bp+38] ; protected mode SS mov ebx,[bp+34] ; protected mode ESP mov si,SELCS ; protected mode CS mov di,off @@intrirqf1 movzx edi,di ; protected mode EIP mov cx,SELDS ; protected mode ES mov ax,cx ; protected mode DS jmp [rmtopmswrout] ; jump back to protected mode @@intrirqf1: copy pdseg,SELPRIVAT,ax add [rmstacktop],RMONESTACKLEN ; adjust realmode stack movzx ebx,[rmstacktop] sub bx,40 and [WORD PTR esp+50],200h ; Change all except IF mov ax,[pdseg:bx+32] ; get real mode flags and ax,NOT 200h ; Clear IF or [esp+50],ax ; set return flags dmemcpyw pdseg,ebx,ss,esp,32 ; copy general registers popad pop gs fs es ds ; restore all registers add esp,4 ; kill interrupt # iretd ; [fold] ] ;═════════════════════════════════════════════════════════════════════════════ ; [fold] [ ; General hardware IRQ handler (faster than above) common_hardirq_handler: REPT 16 push large 2000h ; address of rm int vect jmp short @@hard_handler ENDM HARDIRQ_HANDLER_SIZE = ($ - common_hardirq_handler) / 16 @@hard_handler: push ds es fs gs pushad ; store general registers copy ds,SELDS,ax copy pdseg,SELPRIVAT,ax mov dx,[rmstacktop] movzx ebx,dx sub dx,RMONESTACKLEN cmp dx,[rmstackbase] ; exceeded real mode stack space? jb critical_error ; if yes, critical error (hang) mov [rmstacktop],dx ; update for possible reentrancy mov bp,[esp+40] ; get intvector sub bx,6 ; space on real mode stack mov [pdseg:bx+2],esp ; protected mode stack mov [pdseg:bx+0],ss ; to return to protected mode mov dx,[privatedataseg] ; set dx to real mode ss sub cx,cx ; so 'es' points to IVT mov ax,DGROUP mov si,_TEXT mov di,off @@intrirqf0 jmp [pmtormswrout] ; switch to real mode @@intrirqf0: pushf ; pushf for iret return call [DWORD PTR es:bp] ; jump into rm int handler ; regs won't change, as this is an hardware int @@entr: pop dx ; protected mode SS pop ebx ; protected mode ESP mov si,SELCS ; protected mode CS DB 66h mov di,off @@intrirqf1 ; mov edi,off @@intrirqf1 DW 0 ; protected mode EIP mov cx,SELDS ; protected mode ES mov ax,cx ; protected mode DS jmp [rmtopmswrout] ; jump back to protected mode @@intrirqf1: add [rmstacktop],RMONESTACKLEN ; adjust realmode stack popad pop gs fs es ds ; restore all registers add esp,4 ; kill interrupt # iretd ; [fold] ] ;═════════════════════════════════════════════════════════════════════════════ ; [fold] [ ; handler for NMI interrupt. NMI_exception: pushfd push large cs push 0 call common_int_handler + 2*INT_HANDLER_SIZE DB 66h retf ; [fold] ] ;═════════════════════════════════════════════════════════════════════════════ ; [fold] [ ; special handler for emulating the FPU. IF FAST_FPU_EMU EQ 1 EX_SIZE EQU 100 ; bytes to be made available on the user stack ; djgpp v2 requires 92 bytes (exception structure size) ; in the release version, while beta4 needs 0 FPU_emulation: sub esp,EX_SIZE+6 ; leave required bytes plus slot for ds and edi push ss push esp add [DWORD PTR esp],EX_SIZE+20 ; esp before exception push [DWORD PTR esp+EX_SIZE+20] ; move eflags push [DWORD PTR esp+EX_SIZE+20] ; move cs push [DWORD PTR esp+EX_SIZE+20] ; move eip push eax ; dummy error code push large cs ; return segment db 66h push off FPU_emulation_end ; return address dw 0 db 66h, 0EAh ; jmp far to 32 bit offset FPU_emu_vector Farptr32 <0,0,0> FPU_emulation_end: add esp,4 ; kill error code mov [esp+18],edi ; store edi and ds mov [esp+22],ds sub [dword ptr esp+12],12 ; make room for iret frame lds edi,[esp+12] pop [DWORD PTR ds:edi] ; get EIP pop [DWORD PTR ds:edi+4] ; get CS pop [DWORD PTR ds:edi+8] ; get EFLAGS lds edi,[esp+6] ; restore ds and edi lss esp,[esp] ; switch to requested stack iretd ENDIF ; [fold] ] ;═════════════════════════════════════════════════════════════════════════════ ; [fold] [ ; Exception handler code ; We get here through a task switch. ds is SELPRIVAT, es is SELDS, bx is ; exception number, al is bl & 0f8h, ah is 1<<(bl&7) (both used for user ; int identification), dx is Pdata.exceptionstack, ecx is 0. ; ints are disabled, for details, see vxr_init ASSUME ds:NOTHING common_exception_with_error_handler: push 2 popf ; Clear NT flag, disable ints cmp sp,dx ; Error code on stack? jz short do_user_int ; yes, its an exception pop ecx ; pop error code jmp do_exception common_exception_without_error_handler: push 2 popf ; Clear NT flag, disable ints mov dx,020h ; port for master pic cmp al,[es:picmasternew] je short @@test_hw_int mov dx,0a0h ; port for slave pic cmp al,[es:picslavenew] jne short @@test_sw_int ; This code assumes that the appropriate hardware int is enabled. I may add ; code to fix that, but the probability of this causing trouble is extremely ; low and only possible in strange configurations. @@test_hw_int: mov al,0bh ; read ISR out dx,al ; dx is pic port jmp short $+2 in al,dx cmp al,ah ; mask is already in ah je short do_user_int ; it is an exception ; There is a probability of wrong identification here if an exception occurs ; after an instruction that ends with the sequence 0cdxxh where xx is the ; exception number. @@test_sw_int: mov edi,[ds:Pdata.vcpitss.eip] cmp edi,2 ; is it the beginning of the segment jb do_exception ; so that int instruction doesn't fit? mov ax,[ds:Pdata.vcpitss.cs] mov fs,ax mov ax,[word ptr fs:edi-2] cmp al,0cdh ; is it an int instruction? jne short do_exception cmp ah,bl ; is the int number correct? jne short do_exception ; Here we serve a hardware or software int if it uses the same vector with an ; exception. The registers are restored and we switch to the user task. do_user_int: mov di,[es:vcpi_seltss] mov [ds:di + Pdata.gdt.types],0089h ltr di ; now we are in user task shl bx,3 mov [ds:bx + SELTASKS + Pdata.gdt.types],0089h ; clear busy bit mov ss,[ds:Pdata.vcpitss.ss] ; CPU disables ints for next ins. mov esp,[ds:Pdata.vcpitss.esp] ; switch to user stack ; interrupt frame push [ds:Pdata.vcpitss.eflags] push [DWORD PTR ds:Pdata.vcpitss.cs] push [ds:Pdata.vcpitss.eip] ; handler address push [DWORD PTR ds:bx + Pdata.lowint.sel] push [ds:bx + Pdata.lowint.offset] mov eax,[ds:Pdata.vcpitss.eax] mov ecx,[ds:Pdata.vcpitss.ecx] mov edx,[ds:Pdata.vcpitss.edx] mov ebx,[ds:Pdata.vcpitss.ebx] mov ebp,[ds:Pdata.vcpitss.ebp] mov esi,[ds:Pdata.vcpitss.esi] mov edi,[ds:Pdata.vcpitss.edi] mov es,[ds:Pdata.vcpitss.es] mov fs,[ds:Pdata.vcpitss.fs] mov gs,[ds:Pdata.vcpitss.gs] mov ds,[ds:Pdata.vcpitss.ds] clts DB 66h ; a 32 far return retf ; Here we serve an exception. Error code is in ecx. do_exception: shl bx,3 mov di,[es:vcpi_seltss] mov [ds:di + Pdata.gdt.types],0089h ltr di ; now we are in user task mov [ds:bx + SELTASKS + Pdata.gdt.types],0089h ; clear busy bit push SELCORE ; selector for ss mov eax,[es:pmstacktop] push eax ; top of pmstack sub eax,PMONESTACKLEN ; set EAX to next stack location mov [es:pmstacktop],eax ; update ptr for possible reenterancy cmp eax,[es:pmstackbase] ; exceeded protected mode stack space? jbe critical_error ; if yes, critical error (hang) lss esp,[esp] push [DWORD PTR ds:Pdata.vcpitss.ss] ; build up stack like DPMI says push [ds:Pdata.vcpitss.esp] push [ds:Pdata.vcpitss.eflags] push [DWORD PTR ds:Pdata.vcpitss.cs] push [ds:Pdata.vcpitss.eip] push ecx ; store error code push large SELCS DB 66h push off @@back ; push return address DW 0 push [DWORD PTR ds:bx + Pdata.exceptions.sel] ; push address of push [ds:bx + Pdata.exceptions.offset] ; handler mov eax,[ds:Pdata.vcpitss.eax] mov ecx,[ds:Pdata.vcpitss.ecx] mov edx,[ds:Pdata.vcpitss.edx] mov ebx,[ds:Pdata.vcpitss.ebx] mov ebp,[ds:Pdata.vcpitss.ebp] mov esi,[ds:Pdata.vcpitss.esi] mov edi,[ds:Pdata.vcpitss.edi] mov es,[ds:Pdata.vcpitss.es] mov fs,[ds:Pdata.vcpitss.fs] mov gs,[ds:Pdata.vcpitss.gs] mov ds,[ds:Pdata.vcpitss.ds] DB 66h ; a 32 far return retf @@back: ; if come here, jump back to caller sub [DWORD PTR esp+16],18 ; return interrupt frame in user stack push edi push ds mov edi,[esp+22] ; user esp mov ds,[esp+26] ; user ss pop [WORD PTR ds:edi] ; task's DS pop [DWORD PTR ds:edi+2] ; task's EDI add esp,4 ; Kill error code pop [DWORD PTR ds:edi+6] ; return eip to user stack pop [DWORD PTR ds:edi+10] ; return cs to user stack pop [DWORD PTR ds:edi+14] ; return eflags to user stack lss esp,[esp] ; switch to user stack push SELDS ; restore the pmstack from the user pop ds ; stack in case ints are enabled add [ds:pmstacktop],PMONESTACKLEN pop ds pop edi clts iretd ASSUME ds:DGROUP ; [fold] ] ;═════════════════════════════════════════════════════════════════════════════ ; [fold] [ ; callback handler ; The callbacks are not 100% DPMI compliant. If the callback code doesn't ; update the cs:ip fields of the call structure the callback should be ; entered immediately again. We will hang the computer instead, but this ; practice shouldn't be a real problem. callback: cli cld mov ax,sp add ax,10+32+2+8 ; sp when called push ss ax ; store for later use copy ds,DGROUP,ax mov ebx,[pmstacktop] sub ebx,PMONESTACKLEN ; set EBX to next stack location mov [pmstacktop],ebx ; update ptr for possible reenterancy cmp ebx,[pmstackbase] ; exceeded protected mode stack space? jbe critical_error ; if yes, critical error (hang) add ebx,PMONESTACKLEN ; EBX = top of pmstack xor eax,eax ; EAX = base address of SS mov ax,ss shl eax,4 movzx ebp,sp ; EBP = current linear SS:SP add ebp,eax mov ax,SELCORE ; DS selector for protected mode mov dx,ax ; SS selector = DS selector mov si,SELCS ; target protected mode CS:EIP sub edi,edi mov di,offset @@callbackf0 jmp [rmtopmswrout] ; go to protected mode @@callbackf0: mov edi,[ebp+4] ; get register structure lea esi,[ebp+4+10] ; pointer to saved registers dmemcpyw ds,esi,es,edi,32+2+8 ; copy register to struct sub edi,32+2+8 ; correct edi mov [es:edi+Dpmi_regs.ip],off critical_error mov [es:edi+Dpmi_regs.cs],_TEXT ; in case cs:ip are not updated... mov eax,[ebp] ; get original ss:sp mov [DWORD PTR es:edi+Dpmi_regs.sp],eax pushfd ; push flags for IRETD from callback db 66h ; push 32bit CS for IRETD push cs dw 6866h,@@callbackf1,0 ; push 32bit EIP for IRETD push 0 ; pad stack push [WORD PTR ebp+4+4+4] ; get callback cs push [DWORD PTR ebp+4+4] ; get callback eip db 66h ; 32bit RETF to callback retf @@callbackf1: push es ; DS:ESI = register structure pop ds mov esi,edi copy es,SELCORE,ax ; ES -> 0 (beginning of memory) copy fs,SELDS,ax ; selector for Datasegment add [fs:pmstacktop],PMONESTACKLEN ; correct stack ptr2lin [ds:esi+Dpmi_regs.ss],[ds:esi+Dpmi_regs.sp],di,ax,edi,eax sub edi,32+2+8+4 ; Space for regs on rm stack + jump dmemcpyw ds,esi,es,edi,32+2+8+4 ; copy regs + jump sub esi,32+2+8+4 ; correct ESI mov bx,[ds:esi+Dpmi_regs.sp] sub bx,32+2+8+4 ; BX = real mode SP mov dx,[ds:esi+Dpmi_regs.ss] ; DX = real mode SS mov si,_TEXT ; SI = real mode CS mov di,off @@callbackf2 ; DI = real mode IP jmp [fs:pmtormswrout] ; switch to real mode @@callbackf2: mov bp,sp mov eax,[bp+Dpmi_regs.res] ; get old highword of esp mov ax,sp mov esp,eax ; restore old esp popad ; get callback return general regs popf ; get callback flags pop es ds fs gs ; get callback return segment regs retf ; go to callback return CS:IP ; [fold] ] ;═════════════════════════════════════════════════════════════════════════════ ; [fold] [ ; real mode INT 15h handler int15: push ds push DGROUP pop ds cmp ah,88h ; function 88h? je short @@int15f0 ; if yes, need to process pushf call [oldint15vector] push bp pushf mov bp,sp pop [WORD PTR bp+10] ; store flags pop bp ds iret @@int15f0: pushf ; call old int 15h handler call [oldint15vector] sub ax,[rawextmemused] ; adjust AX by extended memory used push bp ; clear carry flag on stack for IRET mov bp,sp and [byte ptr bp+8],0feh pop bp pop ds iret ; return with new AX extended memory ; [fold] ] ;═════════════════════════════════════════════════════════════════════════════ ; [fold] [ ; Int 21 (shelling out) dos21rm: cmp ax,4B00h ; dos exec call je short @@doit cmp ax,4B03h je short @@doit cmp ax,4B05h je short @@doit jmp short @@exit @@doit: push ax gs fs ds es ; store registers on stack pushad copy ds,DGROUP,ax test [from_us],-1 jnz short @@nous ; int not from us inc [from_us] ; for reentrancy call [ResetMasterPIC] ; reset to default call [ResetA20] mov bp,sp mov ax,[bp+46] mov [bp+40],ax popad pop es ds fs gs call [cs:oldint21vector.ptr] ; call old push gs fs ds es ; save return pushad pushf copy ds,DGROUP,ax call [SetMasterPIC] call [SetA20] dec [from_us] pop ax ; get flags mov bp,sp mov [bp+44],ax ; store for iret popad pop es ds fs gs iret ; return to caller @@nous: popad pop es ds fs gs ax @@exit: DB 0EAh ; jmp far ?:? oldint21vector Farptr16 ? ; [fold] ] ;═════════════════════════════════════════════════════════════════════════════ ; [fold] [ ; Int 23 (ctrl-c) int23pm: ; default pm handler iretd int23rm: ; callbacks to protected mode push gs fs ds es pushad cld cli copy ds,DGROUP,ax mov bp,ss ; save real mode stack for later shl ebp,16 mov bp,sp xor eax,eax ; EAX = base address of SS mov ax,ss shl eax,4 movzx ebx,sp ; EBX = stack in prot. mode add ebx,eax mov ax,SELDS ; DS selector for protected mode mov cx,ax ; ES selector for protected mode mov dx,SELCORE ; SS selector mov si,SELCS ; target protected mode CS:EIP DB 66h mov di,off @@callbackf0 ; mov edi,off @@callbackf0 DW 0 jmp [rmtopmswrout] ; go to protected mode @@callbackf0: push ebp int 23h ; call pm ctrl-c handler pop bx ; BX = real mode SP pop dx ; DX = real mode SS mov si,_TEXT ; SI = real mode CS mov di,off @@callbackf2 ; DI = real mode IP jmp [pmtormswrout] ; switch to real mode @@callbackf2: mov bp,sp mov eax,[bp + Dpmi_regs.res] ; get old highword of esp mov ax,sp mov esp,eax ; restore old esp popad ; get callback return general regs pop es ds fs gs ; get callback return segment regs iret ; [fold] ] ;═════════════════════════════════════════════════════════════════════════════ ; [fold] [ ; Int 24 (critical error) int24pm: ; default pm handler mov al,3 ; fail is default action. I hope it will never iretd ; happen that dos aborts on return int24rm: ; callbacks to protected mode push gs fs ds es pushad cld cli copy ds,DGROUP,ax mov bp,ss ; save real mode stack for later shl ebp,16 mov bp,sp xor eax,eax ; EAX = base address of SS mov ax,ss shl eax,4 movzx ebx,sp ; EBX = stack in prot. mode add ebx,eax mov ax,SELDS ; DS selector for protected mode mov cx,ax ; ES selector for protected mode mov dx,SELCORE ; SS selector mov si,SELCS ; target protected mode CS:EIP DB 66h mov di,off @@callbackf0 ; mov edi,off @@callbackf0 DW 0 jmp [rmtopmswrout] ; go to protected mode @@callbackf0: movzx edx,[esp + Dpmi_regs.bp] shl edx,4 mov ecx,edx shr ecx,16 mov bx,SELINT24 mov ax,0007h int 31h ; set base of INT 24 selector mov ax,[esp + Dpmi_regs.ax] mov si,[esp + Dpmi_regs.si] mov di,[esp + Dpmi_regs.di] push ebp mov bp,SELINT24 int 24h ; call pm critical error handler pop bx ; BX = real mode SP pop dx ; DX = real mode SS mov [esp + Dpmi_regs.al],al ; store return value mov si,_TEXT ; SI = real mode CS mov di,off @@callbackf2 ; DI = real mode IP jmp [pmtormswrout] ; switch to real mode @@callbackf2: mov bp,sp mov eax,[bp + Dpmi_regs.res] ; get old highword of esp mov ax,sp mov esp,eax ; restore old esp popad ; get callback return general regs pop es ds fs gs ; get callback return segment regs iret ; [fold] ] ;═════════════════════════════════════════════════════════════════════════════ ; [fold] [ ; internal int 2f, ax=1680h, ax=1686h or ax=168ah int2fpm: IF PMODEDJ_EXT EQ 1 cmp ax,168ah je short @@int2f168a ENDIF cmp ax,1680h je short @@int2f1680 cmp ax,1686h jne common_int_handler+2fh*INT_HANDLER_SIZE ; if no, go to INT 2fh @@int2f1686: ; Get CPU Mode xor ax,ax ; we are runniing in protected mode iretd @@int2f1680: ; Release Current Virtual Machine's Time Slice pushfd push large cs push 0 call common_int_handler+2fh*INT_HANDLER_SIZE ; pass down to real mode test al,al ; is it supported? je short @@int2f1680ok ; yes, we are done. sti ; give processor a chance to cool down :) hlt ; wait for int. xor al,al @@int2f1680ok: iretd IF PMODEDJ_EXT EQ 1 @@int2f168a: ; Get Vendor-Specific API Entry Point mov ax,0a00h int 31h ; try the extension mov ax,1600h ; prepare ax for succesful exit iretd ENDIF ; [fold] ] ;═════════════════════════════════════════════════════════════════════════════ ; [fold] [ ; real mode INT 2F handler int2frm: iret ; [fold] ] ;═════════════════════════════════════════════════════════════════════════════ ; [fold] [ ; VCPI/XMS/raw save/restore status (called from real mode) vxr_saverestorerm: retf ; no save/restore needed, 16bit RETF ; [fold] ] ;═════════════════════════════════════════════════════════════════════════════ ; [fold] [ ; VCPI/XMS/raw save/restore status (called from protected mode) vxr_saverestorepm: db 66h,0cbh ; no save/restore needed, 32bit RETF ; [fold] ] ;═════════════════════════════════════════════════════════════════════════════ ; [fold] [ ; critical error routine critical_error: ; some unrecoverable error cli ; make sure we are not interrupted in al,61h ; beep or al,3 out 61h,al jmp $ ; now hang ; [fold] ] ;═════════════════════════════════════════════════════════════════════════════ ; [fold] [ ; PIC reprogramming ;───────────────────────────────────────────────────────────────────────────── ; [fold] [ ; Resets the master PIC base v_resetpic: pushf cli call pic_repr ; reprogramming allowed? movzx bx,[picmasterold] movzx cx,[picslaveold] mov ax,0DE0Bh ; VCPI set pic mappings int 67h jmp short xr_ddd xr_resetpic: pushf cli call pic_repr ; reprogramming allowed? xr_ddd: mov cl,[picmasterold] ; set master PIC base to default call Change_PIC movzx di,[picmasternew] ; Clear entries in the IVT shl di,2 setmemw 0,di,8*4 popf ret ; [fold] ] ;───────────────────────────────────────────────────────────────────────────── ; [fold] [ ; Sets the master PIC base v_setpic: pushf cli call pic_repr ; reprogramming allowed? movzx bx,[picmasternew] movzx cx,[picslavenew] mov ax,0DE0Bh ; VCPI set pic mappings int 67h jmp short xr_eee xr_setpic: pushf cli call pic_repr ; reprogramming allowed? xr_eee: mov dx,off pic_ints mov cx,8 movzx bx,[picmasternew] shl bx,2 sub ax,ax mov es,ax @@ww1: mov [es:bx+0],dx ; set offset mov [es:bx+2],cs ; set segment add bx,4 ; next entry add dx,PIC_INT_SIZE ; next int wrapper dec cx jnz @@ww1 mov cl,[picmasternew] call Change_PIC popf ret ; [fold] ] ;----------------------------------------------------------------------------- ; [fold] [ ; Returns to caller, if reprogramming of the master PIC is not allowed. pic_repr: pop bx ; pop return address test [reprogrampic],-1 jz short @@oops mov al,[picmasternew] cmp al,[picmasterold] ; same? jz short @@oops jmp bx ; repromming allowed, return @@oops: popf ; return to caller ret ; [fold] ] ;───────────────────────────────────────────────────────────────────────────── ; [fold] [ ; Reprograms the first PIC ; IN: CL = new master PIC base; Interrupts disabled Change_PIC: in al,21h mov di,ax ; save old state call @@wt mov al,0FFh out 21h,al ; disable master ints call @@wt mov al,11h out 20h,al call @@wt mov al,cl ; set new base out 21h,al call @@wt mov al,4 out 21h,al call @@wt mov al,1 out 21h,al ; init finished here call @@wt mov al,0FFh out 21h,al ; disable master ints again mov ax,di out 21h,al ; restore master ints ret @@wt: in al,80h ; a safe ioport ret ; [fold] ] ;───────────────────────────────────────────────────────────────────────────── ; [fold] [ ; Redirection interrupt handlers. ; Needed so the Compi (hopefully) doesn't crash in real mode when the master ; PIC base is changed. pic_ints: count = 8 REPT 8 push eax push bp ds sub bp,bp mov ds,bp mov eax,[ds:count*4] mov bp,sp xchg eax,[ss:bp+4] pop ds bp retf count = count +1 ENDM PIC_INT_SIZE = ($ - pic_ints) / 8 ; [fold] ] ; [fold] ] ;═════════════════════════════════════════════════════════════════════════════ ; [fold] [ ; A20 control ;───────────────────────────────────────────────────────────────────────────── ; [fold] [ v_seta20: ; Under VCPI A20 is controlled complety by the Memory Manager v_reseta20: ret_only: ret ; [fold] ] ;───────────────────────────────────────────────────────────────────────────── ; [fold] [ x_seta20: ; XMS set A20 mov ah,7 call [xms_call.ptr] ; get current state of A20 mov [olda20],al ; store mov ah,3 ; enable A20 call [xms_call.ptr] ret ; [fold] ] ;───────────────────────────────────────────────────────────────────────────── ; [fold] [ x_reseta20: ; XMS reset A20 mov ah,[olda20] ; get old state of A20 xor ah,1 add ah,3 call [xms_call.ptr] ; set to old state ret ; [fold] ] ;───────────────────────────────────────────────────────────────────────────── ; [fold] [ r_seta20: ; raw set A20 clc ; assume success pushf ; save intena flag cli call enablea20test ; get old state mov [olda20],al ; is A20 already enabled? jz short @@enablea20done ; if yes, done in al,92h ; PS/2 A20 enable or al,2 jmp short $+2 jmp short $+2 jmp short $+2 out 92h,al call enablea20test ; is A20 enabled? jz short @@enablea20done ; if yes, done call enablea20kbwait ; AT A20 enable jnz short @@enablea20f0 mov al,0d1h out 64h,al call enablea20kbwait jnz short @@enablea20f0 mov al,0dfh out 60h,al call enablea20kbwait @@enablea20f0: ; wait for A20 to enable mov cx,800h ; do 800h tries @@enablea20l0: call enablea20test ; is A20 enabled? jz short @@enablea20done ; if yes, done in al,40h ; get current tick counter jmp short $+2 jmp short $+2 jmp short $+2 in al,40h mov ah,al @@enablea20l1: ; wait a single tick in al,40h jmp short $+2 jmp short $+2 jmp short $+2 in al,40h cmp al,ah je @@enablea20l1 loop @@enablea20l0 ; loop for another try mov bp,sp ; error, A20 did not enable or [WORD PTR bp],1 ; set carry @@enablea20done: popf ret ; [fold] ] ;───────────────────────────────────────────────────────────────────────────── ; [fold] [ r_reseta20: ; raw reset A20 ret ; i dont know how to switch off A20 ; [fold] ] ;----------------------------------------------------------------------------- ; [fold] [ enablea20kbwait: ; wait for safe to write to 8042 xor cx,cx @@enablea20kbwaitl0: jmp short $+2 jmp short $+2 jmp short $+2 in al,64h ; read 8042 status test al,2 ; buffer full? loopnz @@enablea20kbwaitl0 ; if yes, loop ret ; [fold] ] ;----------------------------------------------------------------------------- ; [fold] [ enablea20test: ; test for enabled A20 push ds es xor ax,ax ; set A20 test segments 0 and 0ffffh mov ds,ax dec ax mov es,ax mov al,[ds:0] ; get byte from 0:0 mov ah,al ; preserve old byte not al ; modify byte xchg al,[es:10h] ; put modified byte to 0ffffh:10h cmp ah,[ds:0] ; set zero if byte at 0:0 not modified mov [es:10h],al ; put back old byte at 0ffffh:10h sete al cbw pop es ds ret ; return, zero if A20 enabled ; [fold] ] ; [fold] ] ;═════════════════════════════════════════════════════════════════════════════ ; [fold] [ ; internal int 21, ah=4C int21: cmp ah,4ch ; AH = 4Ch? jne common_int_handler+21h*INT_HANDLER_SIZE ; if no, go to INT 21h push ax ; save return value copy ds,SELDS,ax copy coreseg,SELCORE,ax mov eax,[oldint15vector] ; put back old INT 15h handler mov [coreseg:4*15h],eax mov eax,[oldint2fvector] ; put back old multiplex mov [coreseg:4*2fh],eax mov eax,[cs:oldint21vector.ptr] ; put back old INT 21h handler mov [coreseg:4*21h],eax mov ebx,cr0 ; restore EM bit and ebx,NOT 4 mov al,[oldCR0L] and al,4 or bl,al mov cr0,ebx mov ax,DGROUP mov cx,ax mov dx,ax mov bx,off endstack-2 pop [WORD PTR bx] ; put returnvalue on real mode stack mov si,_TEXT mov di,off @@come jmp [pmtormswrout] ; switch to real mode @@come: movzx bx,[pmodetype] add bx,bx call [exitrouttbl+bx] ; deinit mov es,[privatedataseg] mov ah,49h int 21h ; free private data call [pm_exit] ; user defined cleanup routine pop ax int 21h ; quit ;----------------------------------------------------------------------------- ; [fold] [ ; deinit VCPI v_exit: call [ResetMasterPIC] ; default PIC mappings mov dx,[emspage] ; emspage allocated? cmp dx,-1 jz short @@ok1 ; if not, skip mov ah,45h int 67h ; free emspage @@ok1: ret ; [fold] ] ;----------------------------------------------------------------------------- ; [fold] [ ; deinit XMS/raw x_exit: r_exit: call [ResetMasterPIC] ; default PIC mappings call [ResetA20] ; default A20 state ret ; [fold] ] ; [fold] ] ; [fold] ] ;▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒ ; INT 31h INTERFACE ;▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒ ; [fold] [ ;═════════════════════════════════════════════════════════════════════════════ ; [fold] [ int31: ; protected mode INT 31h handler cli cld push ds es fs gs ; push regs needed pushad copy coreseg,SELCORE,ax copy pdseg,SELPRIVAT,ax copy ds,SELDS,ax ; set up selectors mov ax,[esp+Dpmi_regs.ax] ; restore ax push bx mov bx,(INT31FUNCNUM - 1) * 2 ; number of functions to check @@int31l0: cmp ax,[int31functbl+bx] ; found function value? jne short @@int31l0c mov bx,[int31routtbl+bx] ; yes, go to appropriate handler xchg bx,[esp] ret @@int31l0c: sub bx,2 ; no, continue loop jnc @@int31l0 pop bx ; no function found jmp short int31fail8001 ; error 8001h ; [fold] ] ;----------------------------------------------------------------------------- ; [fold] [ ; int 31 fail labels int31fail8024: ; INT 31h return fail with error 8024h mov [word ptr esp+28],8024h ; set AX on stack to 8024h for POPAD jmp short int31fail ;----------------------------------------------------------------------------- int31fail8023: ; INT 31h return fail with error 8023h mov [word ptr esp+28],8023h ; set AX on stack to 8023h for POPAD jmp short int31fail ;----------------------------------------------------------------------------- int31fail8022: ; INT 31h return fail with error 8022h mov [word ptr esp+28],8022h ; set AX on stack to 8022h for POPAD jmp short int31fail ;----------------------------------------------------------------------------- int31fail8021: ; INT 31h return fail with error 8021h mov [word ptr esp+28],8021h ; set AX on stack to 8021h for POPAD jmp short int31fail ;----------------------------------------------------------------------------- int31fail8016: ; INT 31h return fail with error 8016h mov [word ptr esp+28],8016h ; set AX on stack to 8016h for POPAD jmp short int31fail ;----------------------------------------------------------------------------- int31fail8015: ; INT 31h return fail with error 8015h mov [word ptr esp+28],8015h ; set AX on stack to 8015h for POPAD jmp short int31fail ;----------------------------------------------------------------------------- int31fail8013: ; INT 31h return fail with error 8013h mov [word ptr esp+28],8013h ; set AX on stack to 8013h for POPAD jmp short int31fail ;----------------------------------------------------------------------------- int31fail8012: ; INT 31h return fail with error 8012h mov [word ptr esp+28],8012h ; set AX on stack to 8012h for POPAD jmp short int31fail ;----------------------------------------------------------------------------- int31fail8011: ; INT 31h return fail with error 8011h mov [word ptr esp+28],8011h ; set AX on stack to 8011h for POPAD jmp short int31fail ;----------------------------------------------------------------------------- int31fail8010: ; INT 31h return fail with error 8010h mov [word ptr esp+28],8010h ; set AX on stack to 8010h for POPAD jmp short int31fail ;----------------------------------------------------------------------------- int31fail8003: ; INT 31h return fail with error 8003h mov [word ptr esp+28],8003h ; set AX on stack to 8003h for POPAD jmp short int31fail ;----------------------------------------------------------------------------- int31fail8001: ; INT 31h return fail with error 8001h mov [word ptr esp+28],8001h ; set AX on stack to 8001h for POPAD jmp short int31fail ;----------------------------------------------------------------------------- int31failcx: ; INT 31h return fail with CX,AX mov [word ptr esp+24],cx ; put CX onto stack for POPAD ;----------------------------------------------------------------------------- int31failax: ; INT 31h return fail with AX mov [word ptr esp+28],ax ; put AX onto stack for POPAD ;----------------------------------------------------------------------------- int31fail: ; INT 31h return fail, pop all regs popad pop gs fs es ds ;----------------------------------------------------------------------------- int31failnopop: ; INT 31h return fail with carry set or [byte ptr esp+8],1 ; set carry in EFLAGS on stack iretd ;----------------------------------------------------------------------------- int31okedx: ; INT 31h return ok with EDX,CX,AX mov [esp+20],edx ; put EDX onto stack for POPAD jmp short int31okcx ;----------------------------------------------------------------------------- int31okdx: ; INT 31h return ok with DX,CX,AX mov [esp+20],dx ; put DX onto stack for POPAD jmp short int31okcx ;----------------------------------------------------------------------------- int31oksinoax: ; INT 31h return ok SI,DI,BX,CX mov ax,[esp+28] ; get old value of AX for restore ;----------------------------------------------------------------------------- int31oksi: ; INT 31h return ok SI,DI,BX,CX,AX mov [esp+4],si ; put SI onto stack for POPAD mov [esp],di ; put DI onto stack for POPAD mov [esp+16],bx ; put BX onto stack for POPAD ;----------------------------------------------------------------------------- int31okcx: ; INT 31h return ok with CX,AX mov [esp+24],cx ; put CX onto stack for POPAD ;----------------------------------------------------------------------------- int31okax: ; INT 31h return ok with AX mov [esp+28],ax ; put AX onto stack for POPAD ;----------------------------------------------------------------------------- int31ok: ; INT 31h return ok, pop all regs popad pop gs fs es ds ;----------------------------------------------------------------------------- int31oknopop: ; INT 31h return ok with carry clear and [byte ptr esp+8],0feh ; clear carry in EFLAGS on stack iretd ; [fold] ] ; [fold] ] ;▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒ ; DESCRIPTOR FUNCTIONS ;▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒ ; [fold] [ ;----------------------------------------------------------------------------- ; [fold] [ int31testsel: ; test for valid selector BX pop bp ; pop return address movzx ebx,bx mov edi,[gdtbase] cmp bx,[gdtlimit] ; selector BX out of range? ja int31fail8022 ; if yes, fail with error 8022h test bl,7 ; index in LDT? Or wrong RPL? jnz int31fail8022 ; Only GDT allowed and bl,0f8h ; mask offset table index and RPL test [byte ptr coreseg:6+ebx+edi],10h; is descriptor used? jz int31fail8022 ; if descriptor not used, fail 8022h jmp bp ; return ok ; [fold] ] ;----------------------------------------------------------------------------- ; [fold] [ int31testaccess: ; test access bits in CX pop bp ; pop return address test ch,20h ; test MUST BE 0 bit in CH jnz int31fail8021 ; if not 0, error 8021h test cl,90h ; test present and MUST BE 1 bits jz int31fail8021 ; if both 0, error 8021h jpo int31fail8021 ; if unequal, error 8021h test cl,60h ; test DPL jnz int31fail8021 ; if not 0, error 8021h test cl,8 ; if code, more tests needed jz short @@int31testselok ; if data, skip code tests test cl,2 ; readable? jz int31fail8021 test cl,4 ; non-conform? jnz int31fail8021 @@int31testselok: jmp bp ; return ok ; [fold] ] ;───────────────────────────────────────────────────────────────────────────── ; [fold] [ int310000: ; allocate descriptors or cx,cx ; if CX = 0, error 8021h jz int31fail8021 mov edx,[gdtbase] ; get base of GDT movzx eax,[gdtlimit] ; EAX = last selector index and al,0f8h mov bx,cx ; BX = number of selectors to find @@int310000l0: test [byte ptr coreseg:edx+eax+6],10h; is descriptor used? jnz short @@int310000l0f0 dec bx ; found free descriptor, dec counter jnz short @@int310000l0f1 ; continue if need to find more mov ebx,eax ; found all descriptors requested @@int310000l1: mov [dword ptr coreseg:edx+ebx],0 ; set entire new descriptor mov [dword ptr coreseg:edx+ebx+4],109200h add bx,8 ; increment selector index dec cx ; dec counter of descriptors to mark jnz @@int310000l1 ; loop if more to mark jmp int31okax ; return ok, with AX @@int310000l0f0: mov bx,cx ; reset number of selectors to find @@int310000l0f1: sub ax,8 ; dec current selector counter cmp ax,8*SYSSELECTORS ; more descriptors to go? jae @@int310000l0 ; if yes, loop jmp int31fail8011 ; did not find descriptors ; [fold] ] ;───────────────────────────────────────────────────────────────────────────── ; [fold] [ int310001: ; free descriptor call int31testsel ; test for valid selector BX mov ax,ss cmp bx,ax ; free stackselector? jz int31fail8022 ; never do this! cmp bx,[esp+32+8+4] ; free codeselector? jz int31fail8022 and [byte ptr coreseg:edi+ebx+6],0efh; mark descriptor as free and [byte ptr coreseg:edi+ebx+5],07Fh; clear present bit mov cx,4 ; zero any segregs loaded with BX lea ebp,[esp+32] ; EBP -> selectors on stack @@int310001l0: cmp [word ptr ebp],bx ; selector = BX? jne short @@int310001l0f0 ; if no, continue loop mov [word ptr ebp],0 ; zero selector on stack @@int310001l0f0: add ebp,2 ; increment selector ptr loop @@int310001l0 ; loop jmp int31ok ; return ok ; [fold] ] ;───────────────────────────────────────────────────────────────────────────── ; [fold] [ int310002: ; segment to selector mov si,off segmentbases ; check, if segment already mapped @@lp1: mov ax,[si + 0] ; load selector to ax test ax,ax ; selector valid? jz short @@skp cmp bx,[si + 2] ; compare segment values jz int31okax @@skp: add si,4 cmp si,off segmentbases + segmentbases_SIZE jb @@lp1 mov si,off segmentbases ; search for a free entry @@lp2: test [word ptr si],-1 ; this field free? jz short @@skp2 ; if so, use it add si,4 cmp si,off segmentbases + segmentbases_SIZE jb @@lp2 jmp int31fail8010 ; no entry free @@skp2: mov [si + 2],bx ; store segment movzx edi,bx ; convert to linear address shl edi,4 mov cx,1 sub ax,ax int 31h ; allocate selector jc int31failax mov [si + 0],ax ; store selector mov bx,ax sub cx,cx mov dx,-1 mov ax,8 int 31h ; set descriptor limit mov dx,di shr edi,16 mov cx,di mov ax,7 int 31h ; set descriptor base - cannot fail mov cx,4092h mov ax,9 int 31h ; set access rights mov ax,bx ; return selector jmp int31okax ; [fold] ] ;───────────────────────────────────────────────────────────────────────────── ; [fold] [ int310003: ; get selector increment value mov ax,8 ; selector increment value is 8 jmp int31okax ; return ok, with AX ; [fold] ] ;───────────────────────────────────────────────────────────────────────────── ; [fold] [ int310006: ; get segment base address call int31testsel ; test for valid selector BX mov dx,[word ptr coreseg:edi+ebx+2] ; low word of 32bit linear addr mov cl,[byte ptr coreseg:edi+ebx+4] ; high word of 32bit linear addr mov ch,[byte ptr coreseg:edi+ebx+7] jmp int31okdx ; return ok, with DX, CX, AX ; [fold] ] ;───────────────────────────────────────────────────────────────────────────── ; [fold] [ int310007: ; set segment base address call int31testsel ; test for valid selector BX mov [word ptr coreseg:edi+ebx+2],dx ; low word of 32bit linear addr mov [byte ptr coreseg:edi+ebx+4],cl ; high word of 32bit linear addr mov [byte ptr coreseg:edi+ebx+7],ch jmp int31ok ; return ok ; [fold] ] ;───────────────────────────────────────────────────────────────────────────── ; [fold] [ int310008: ; set segment limit call int31testsel ; test for valid selector BX cmp cx,0fh ; limit greater than 1M? jbe short @@int310008f0 ; Current DJGPP code doesn't work with limit check, so... ; mov ax,dx ; yup, limit greater than 1M ; and ax,0fffh ; cmp ax,0fffh ; low 12 bits set? ; jne int31fail8021 ; if no, error 8021h shrd dx,cx,12 ; DX = low 16 bits of page limit shr cx,12 ; CL = high 4 bits of page limit or cl,80h ; set granularity bit in CL @@int310008f0: mov [word ptr coreseg:edi+ebx],dx ; put low word of limit and [byte ptr coreseg:edi+ebx+6],70h ; mask off G and high nybble of limit or [byte ptr coreseg:edi+ebx+6],cl ; put high nybble of limit jmp int31ok ; return ok ; [fold] ] ;───────────────────────────────────────────────────────────────────────────── ; [fold] [ int310009: ; set descriptor access rights call int31testsel ; test for valid selector BX call int31testaccess ; test access bits in CX or ch,10h ; set AVL bit, descriptor used and ch,0f0h ; mask off low nybble of CH and [byte ptr coreseg:edi+ebx+6],0fh ; mask off high nybble access rights or [byte ptr coreseg:edi+ebx+6],ch ; or in high access rights byte mov [byte ptr coreseg:edi+ebx+5],cl ; put low access rights byte jmp int31ok ; return ok ; [fold] ] ;───────────────────────────────────────────────────────────────────────────── ; [fold] [ int31000a: ; create alias descriptor call int31testsel ; test for valid selector BX mov ax,0000h ; allocate descriptor mov cx,1 int 31h jc int31fail8011 ; if failed, descriptor unavailable push ax ; preserve allocated selector movzx edi,ax ; EDI = target selector mov esi,[gdtbase] ; ESI -> GDT copy [coreseg:esi+edi],[coreseg:esi+ebx],eax mov eax,[coreseg:esi+ebx+4] ; copy descriptor data mov ah,92h mov [coreseg:esi+edi+4],eax pop ax ; restore allocated selector jmp int31okax ; return ok, with AX ; [fold] ] ;───────────────────────────────────────────────────────────────────────────── ; [fold] [ int31000b: ; get descriptor call int31testsel ; test for valid selector BX lea esi,[edi+ebx] ; ESI -> descriptor in GDT mov edi,[esp] ; get EDI buffer ptr from stack copy [es:edi+0],[coreseg:esi+0],eax ; copy descriptor copy [es:edi+4],[coreseg:esi+4],eax jmp int31ok ; return ok ; [fold] ] ;───────────────────────────────────────────────────────────────────────────── ; [fold] [ int31000c: ; set descriptor call int31testsel ; test for valid selector BX mov esi,[esp] ; ESI = EDI buffer ptr from stack mov cx,[es:esi+5] ; get access rights from descriptor call int31testaccess ; test access bits in CX add edi,ebx ; adjust EDI to descriptor in GDT copy [coreseg:edi],[es:esi],eax mov eax,[es:esi+4] or eax,100000h ; set descriptor AVL bit mov [coreseg:edi+4],eax jmp int31ok ; return ok ; [fold] ] ;───────────────────────────────────────────────────────────────────────────── ; [fold] [ int31000e: ; get multiple descriptors mov ax,000bh ; function 000bh, get descriptor ;----------------------------------------------------------------------------- int31000ef: ; common to funcions 000eh and 000fh or cx,cx ; if CX = 0, return ok immediately jz int31ok mov dx,cx ; DX = number of descriptors xor cx,cx ; CX = successful counter @@int31000efl0: mov bx,[es:edi] ; BX = selector to get add edi,2 int 31h ; get/set descriptor jc int31failcx ; if error, fail with AX and CX add edi,8 ; increment descriptor ptr inc cx ; increment successful copy counter dec dx ; decrement loop counter jnz @@int31000efl0 ; if more descriptors to go, loop jmp int31ok ; return ok ; [fold] ] ;───────────────────────────────────────────────────────────────────────────── ; [fold] [ int31000f: ; set multiple descriptors mov ax,000ch ; function 000ch, set descriptor jmp int31000ef ; go to common function ; [fold] ] ; [fold] ] ;▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒ ; DOS MEMORY FUNCTIONS ;▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒ ; [fold] [ ;----------------------------------------------------------------------------- ; [fold] [ int31010getdosbase: pop bp ; return address mov si,dx ; save selector for later use mov bx,si mov ax,6 int 31h ; Get base of selector jc int31failax ; fail, if selector invalid test dx,0Fh ; not paragraph aligned? jnz int31failax ; not a valid segment address shrd dx,cx,4 ; make segment address test cx,0FFF0h ; above first MB border? jnz int31fail8021 ; if so, fail jmp bp ; else selector and address ok ; [fold] ] ;----------------------------------------------------------------------------- ; [fold] [ int31010issueint: pop bp mov [esp + Dpmi_regs.es],dx mov [esp + Dpmi_regs.ss],0 mov [esp + Dpmi_regs.sp],0 ; no own stack mov edi,esp copy es,ss,ax mov bx,21h ; dos int, no reset of PICs and A20 sub cx,cx ; no stack params to copy mov ax,300h int 31h ; make dos interrupt jnc short @@ok add esp,SIZE Dpmi_regs jmp int31failax @@ok: mov cx,[esp + Dpmi_regs.flags] mov ax,[esp + Dpmi_regs.ax] mov bx,[esp + Dpmi_regs.bx] add esp,SIZE Dpmi_regs ; correct stack test cx,1 ; allocation successful? jz short @@away mov [esp + Dpmi_regs.bx],bx ; return max. # of paragraphs jmp int31failax @@away: jmp bp ; [fold] ] ;───────────────────────────────────────────────────────────────────────────── ; [fold] [ int310100: ; Allocate DOS memory block sub esp,SIZE Dpmi_regs ; space for real mode registers mov [esp + Dpmi_regs.ax],4800h ; dos function allocate memory mov [esp + Dpmi_regs.bx],bx ; # of paragraphs call int31010issueint ; attempt to allocate memory mov si,ax ; save segment for later use sub ax,ax ; Allocate Descriptor mov cx,1 ; 1 is enough for 32bit code int 31h ; try to get one jc short @@failfree ; fail, if no descriptor free mov bx,ax ; BX = DOS mem selector mov cx,4092h ; data descriptor mov ax,9 int 31h ; set descriptor type movzx ecx,[esp + Dpmi_regs.bx] ; get size shl ecx,4 dec ecx mov dx,cx shr ecx,16 mov ax,8 int 31h ; Set descriptor limit mov cx,si ; CX = highword of linear address mov dx,cx ; DX = lowword of linear address shr cx,12 shl dx,4 mov ax,7 int 31h ; set descriptor base mov ax,si ; initial real mode segment mov [esp + Dpmi_regs.dx],bx ; store selector jmp int31okax ; return successful @@failfree: sub esp,SIZE Dpmi_regs ; space for real mode registers mov [esp + Dpmi_regs.ax],4900h ; dos function free memory mov dx,si ; segment call int31010issueint ; free memory jmp int31fail8011 ; and fail ; [fold] ] ;───────────────────────────────────────────────────────────────────────────── ; [fold] [ int310101: ; Free DOS memory block call int31010getdosbase ; check selector and get segment addr mov bx,si mov ax,1 int 31h ; free associated selector sub esp,SIZE Dpmi_regs ; space for real mode registers mov [esp + Dpmi_regs.ax],4900h ; dos function free memory call int31010issueint ; attempt to free memory jmp int31okax ; else return no error ; [fold] ] ;───────────────────────────────────────────────────────────────────────────── ; [fold] [ int310102: ; Resize DOS memory block mov di,bx ; save size for later use call int31010getdosbase ; check selector and segment addr sub esp,SIZE Dpmi_regs ; space for real mode registers mov [esp + Dpmi_regs.ax],4A00h ; dos function resize memory mov [esp + Dpmi_regs.bx],di ; new size call int31010issueint ; attempt to resize memory movzx ecx,[esp + Dpmi_regs.bx] ; get size again shl ecx,4 dec ecx mov dx,cx shr cx,16 mov bx,[esp + Dpmi_regs.dx] ; get selector mov ax,8 int 31h ; Set descriptor limit jmp int31okax ; [fold] ] ; [fold] ] ;▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒ ; INTERRUPT FUNCTIONS ;▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒ ; [fold] [ ;───────────────────────────────────────────────────────────────────────────── ; [fold] [ int310200: ; get real mode interrupt vector movzx ebx,bl ; EBX = BL (interrupt number) mov dx,[coreseg:ebx*4] ; load real mode vector offset mov cx,[coreseg:ebx*4+2] ; load real mode vector segment jmp int31okdx ; return ok, with AX, CX, DX ; [fold] ] ;───────────────────────────────────────────────────────────────────────────── ; [fold] [ int310201: ; set real mode interrupt vector movzx ebx,bl ; EBX = BL (interrupt number) mov [coreseg:ebx*4],dx ; set real mode vector offset mov [coreseg:ebx*4+2],cx ; set real mode vector segment jmp int31ok ; return ok ; [fold] ] ;───────────────────────────────────────────────────────────────────────────── ; [fold] [ int310202: ; get exception handler cmp bl,31 ; Check exception number ja int31fail8021 movzx ebx,bl mov cx,[pdseg:ebx*SIZE Farptr32 + Pdata.exceptions.sel] mov edx,[pdseg:ebx*SIZE Farptr32 + Pdata.exceptions.offset] mov ax,202h ; no error code jmp int31okedx ; [fold] ] ;───────────────────────────────────────────────────────────────────────────── ; [fold] [ int310203: ; set exception handler cmp bl,31 ; Check exception number ja int31fail8021 xchg bx,cx ; swap int number with int selector call int31testsel ; test for valid selector BX movzx ecx,cl mov [pdseg:ecx*SIZE Farptr32 + Pdata.exceptions.pad],0 mov [pdseg:ecx*SIZE Farptr32 + Pdata.exceptions.sel],bx mov [pdseg:ecx*SIZE Farptr32 + Pdata.exceptions.offset],edx IF FAST_FPU_EMU EQ 1 copy es,SELALIASCS,ax mov ax,[pdseg:7*SIZE Farptr32 + Pdata.exceptions.sel] mov [es:FPU_emu_vector.sel],ax mov eax,[pdseg:7*SIZE Farptr32 + Pdata.exceptions.offset] mov [es:FPU_emu_vector.offset],eax ENDIF jmp int31ok ; [fold] ] ;───────────────────────────────────────────────────────────────────────────── ; [fold] [ int310204: ; get protected mode interrupt vector movzx ebx,bl ; EBX = BL (interrupt number) cmp bl,NUM_EXCEPTIONS jae short @@ok3 mov cx,[pdseg:ebx*SIZE Farptr32 + Pdata.lowint.sel] mov edx,[pdseg:ebx*SIZE Farptr32 + Pdata.lowint.offset] mov ax,204h jmp int31okedx @@ok3: mov dx,[pdseg:ebx*8+Pdata.idt.offset1] ; get high word of offset shl edx,16 mov dx,[pdseg:ebx*8+Pdata.idt.offset0] ; get low word of offset mov cx,[pdseg:ebx*8+Pdata.idt.sel] ; get selector mov ax,204h jmp int31okedx ; return ok, with AX, CX, EDX ; [fold] ] ;───────────────────────────────────────────────────────────────────────────── ; [fold] [ int310205: ; set protected mode interrupt vector xchg bx,cx ; swap int number with int selector call int31testsel ; test for valid selector BX movzx ecx,cl ; ECX = CL (interrupt number) ; This code sets the requested int number and if it is a hardware int on the ; master pic, then the actual irq int is set as well. The only problem is that ; requests to set one of the actual irq's will fail with error 8003h (system ; integrity). One possible solution is to reprogram the offending pic in such ; a case, but I won't bother for the time being. mov al,cl and al,0f8h cmp al,[picmasterold] jne short @@notmaster ; set master pic int call @@setint sub cl,[picmasterold] add cl,[picmasternew] call @@setint jmp int31ok @@notmaster: cmp al,[picmasternew] je int31fail8003 ; we should reprogram the pic to another base instead call @@setint jmp int31ok ;----------------------------------------------------------------------------- @@setint: cmp cl,NUM_EXCEPTIONS jae short @@setint1 mov [pdseg:ecx*SIZE Farptr32 + Pdata.lowint.pad],0 mov [pdseg:ecx*SIZE Farptr32 + Pdata.lowint.sel],bx mov [pdseg:ecx*SIZE Farptr32 + Pdata.lowint.offset],edx ret @@setint1: mov [pdseg:ecx*8+Pdata.idt.offset0],dx ; set low word of offset shld eax,edx,16 mov [pdseg:ecx*8+Pdata.idt.offset1],ax ; set high word of offset mov [pdseg:ecx*8+Pdata.idt.sel],bx ; set selector ret ; [fold] ] ;───────────────────────────────────────────────────────────────────────────── ; [fold] [ int310900: ; get and disable interrupt state btc [word ptr esp+48],9 ; test and clear IF bit in EFLAGS setc al ; set AL = carry (IF flag from EFLAGS) jmp int31okax ; return ok ; [fold] ] ;───────────────────────────────────────────────────────────────────────────── ; [fold] [ int310901: ; get and enable interrupt state bts [word ptr esp+48],9 ; test and set IF bit in EFLAGS setc al ; set AL = carry (IF flag from EFLAGS) jmp int31okax ; return ok ; [fold] ] ;───────────────────────────────────────────────────────────────────────────── ; [fold] [ int310902: ; get interrupt state bt [word ptr esp+48],9 ; just test IF bit in EFLAGS setc al ; set AL = carry (IF flag from EFLAGS) jmp int31okax ; return ok ; [fold] ] ; [fold] ] ;▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒ ; REAL/PROTECTED MODE TRANSLATION FUNCTIONS ;▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒ ; [fold] [ ;───────────────────────────────────────────────────────────────────────────── ; [fold] [ int310300: ; simulate real mode interrupt movzx eax,bl ; get real mode INT CS:IP mov eax,[coreseg:eax*4] mov [DWORD PTR es:edi+Dpmi_regs.ip],eax ; [fold] ] ;───────────────────────────────────────────────────────────────────────────── int310301: ; call real mode FAR procedure ; same start as function 0302h ;───────────────────────────────────────────────────────────────────────────── int310302: ; call real mode IRET procedure ;----------------------------------------------------------------------------- ; [fold] [ int3103: ; common to 0300h, 0301h, and 0302h movzx ebx,[es:edi+Dpmi_regs.sp] ; EBX = SP from register structure movzx edx,[es:edi+Dpmi_regs.ss] ; EDX = SS from register structure mov ax,bx ; check if caller provided stack or ax,dx jnz short @@int3103f3 ; if yes, go on to set stack mov dx,[privatedataseg] ; real mode SS mov bx,[rmstacktop] ; BX = top of real mode stack mov ax,bx ; save top of stack sub bx,RMONESTACKLEN ; adjust BX to next stack location cmp bx,[rmstackbase] ; exceeded real mode stack space? jb int31fail8012 ; if yes, error 8012h mov [rmstacktop],bx ; update ptr for possible reenterancy mov bx,ax ; restore top of stack @@int3103f3: shl edx,4 ; convert seg:ofs form to linear mov edi,edx ; address add edi,ebx ; EDI = top of real mode stack sub edi,10 lea ax,[bx-10] ; AX = top of stack parms xchg ax,[rmstackparmtop] ; preserve and set new top of stack push ax ; parms for possible reenterancy mov [coreseg:edi+8],cx ; store # of parameters mov [coreseg:edi+6],ss ; store SS:ESP on real mode stack mov [coreseg:edi+2],esp ; ESP when switching to real mode mov [coreseg:edi+0],es ; store ES on real mode stack movzx ecx,cx lea esi,[esp+ecx*2+2+32+8+12] ; start of parameters on stack mov ebx,ecx jmp short @@lp1in @@lp1: sub esi,2 mov ax,[ss:esi] sub edi,2 mov [coreseg:edi],ax ; copy parameters @@lp1in:dec ebx jns @@lp1 mov esi,[esp+2+Dpmi_regs.edi] ; call struct mov ax,[es:esi+Dpmi_regs.flags] ; AX = flags for real mode cmp [esp+2+Dpmi_regs.ax],301h ; if function 301h, no space for flags jz short @@w1 and ah,0fch ; 0300h or 0302h, clear IF and TF flag mov [es:esi+Dpmi_regs.flags],ax sub edi,2 ; push flags for IRET stack frame mov [coreseg:edi],ax @@w1: mov [WORD PTR coreseg:edi-4],off @@int3103f1 mov [WORD PTR coreseg:edi-2],_TEXT copy <[DWORD PTR coreseg:edi-8]>,<[DWORD PTR es:esi+Dpmi_regs.ip]>,eax sub edi,8+42 dmemcpyw es,esi,coreseg,edi,42 ; copy registers + flags sub edi,42 ; correct edi sub edi,edx mov ax,DGROUP ; AX = Real Mode DS movzx ebx,di ; EBX = Real Mode ESP shr edx,4 ; DX = Real Mode SS mov si,_TEXT ; SI = Real Mode CS mov di,off @@int3103f0 ; DI = Real Mode IP jmp [pmtormswrout] ; switch to real mode @@int3103f0: ; real mode INT, FAR, or IRET call popad ; load regs with call values popf ; load flags with call value pop es ds fs gs ; load sregs with call values retf ; go to call address @@int3103f1: push gs fs ds es ; store registers on stack pushf ; store flags on stack cli pushad copy ds,DGROUP,ax mov bp,[rmstackparmtop] mov cx,[bp+0] ; get protected mode ES from stack mov ebx,[bp+2] ; get protected mode SS:ESP from stack mov dx,[bp+6] mov bp,ss ; EBP = linear ptr to SS movzx ebp,bp shl ebp,4 mov ax,SELDS ; DS selector value for protected mode mov si,SELCS ; target CS:EIP in protected mode do16to32 mov,di,<off @@int3103f2> jmp [rmtopmswrout] ; go back to protected mode @@int3103f2: copy coreseg,SELCORE,ax copy pdseg,SELPRIVAT,ax movzx eax,[rmstackparmtop] add ebp,eax ; EBP = linear address of rm stack pop [rmstackparmtop] movzx eax,[WORD PTR coreseg:ebp+8] ; get paramcount add eax,eax sub ebp,eax lea esi,[ebp-42] mov edi,[esp+Dpmi_regs.edi] ; get structure offset from stack dmemcpyw coreseg,esi,es,edi,42 ; copy regs and flags cmp [dword ptr es:edi+4],0 ; stack provided by caller? jne int31ok ; if yes, done now add [rmstacktop],RMONESTACKLEN ; restore top of real mode stack jmp int31ok ; return ok ; [fold] ] ;───────────────────────────────────────────────────────────────────────────── ; [fold] [ int310303: ; allocate real mode callback address mov dx,CALLBACKS ; DX = total number of callbacks mov bx,off common_callbacks ; BX = base of callbacks jmp short @@in @@int310303l0: cmp [bx+Callback.ds],0 ; is this callback free? jz short @@int310303f0 ; if yes, allocate add bx,SIZE Callback ; increment ptr to callback @@in: dec dx ; decrement loop counter jns @@int310303l0 ; if more callbacks to check, loop jmp int31fail8015 ; no free callback, error 8015h @@int310303f0: mov cx,[esp+38] ; CX = caller DS from stack mov [bx+Callback.ds],cx ; store callback parms in callback mov [bx+Callback.esi],esi mov [bx+Callback.es],es mov [bx+Callback.edi],edi mov [bx+Callback.ptr.offset],off callback mov [bx+Callback.ptr.sel],_TEXT mov dx,bx ; DX = offset of callback mov cx,DGROUP ; CX = segment of callback jmp int31okdx ; return ok, with DX, CX, AX ; [fold] ] ;───────────────────────────────────────────────────────────────────────────── ; [fold] [ int310304: ; free real mode callback address cmp cx,DGROUP ; valid callback segment? jne int31fail8024 ; if no, error 8024h mov bx,dx ; BX = offset of callback xor ax,ax ; check if valid offset xchg dx,ax sub ax,off common_callbacks mov cx,SIZE Callback div cx or dx,dx ; is there a remainder jnz int31fail8024 ; if yes, not valid, error 8024h cmp ax,CALLBACKS ; callback index out of range? jae int31fail8024 ; if yes, not valid, error 8024h mov [bx+Callback.ds],0 ; set callback free jmp int31ok ; return ok ; [fold] ] ; [fold] ] ;▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒ ; MISC FUNCTIONS ;▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒ ; [fold] [ ;───────────────────────────────────────────────────────────────────────────── ; [fold] [ int310305: ; get state save/restore addresses add esp,20h ; adjust stack xor ax,ax ; size needed is none mov bx,_TEXT ; real mode seg of same RETF mov cx,off vxr_saverestorerm ; same offset of 16bit RETF mov si,cs ; selector of routine is this one DB 66h mov di,off vxr_saverestorepm ; offset of simple 32bit RETF DW 0 pop gs fs es ds ; restore segment registers jmp int31oknopop ; return ok, dont pop registers ; [fold] ] ;───────────────────────────────────────────────────────────────────────────── ; [fold] [ int310306: ; get raw mode switch addresses add esp,20h ; adjust stack mov si,cs ; selector of pmtorm rout is this one movzx edi,[pmtormswrout] ; offset in this seg of rout mov bx,_TEXT ; real mode seg of rmtopm rout mov cx,[rmtopmswrout] ; offset of rout in real mode pop gs fs es ds ; restore segment registers jmp int31oknopop ; return ok, dont pop registers ; [fold] ] ;───────────────────────────────────────────────────────────────────────────── ; [fold] [ int310400: ; get version add esp,20h ; adjust stack mov ax,90 ; return version 0.90 mov bx,3 ; capabilities mov cl,[processortype] ; processor type mov dl,[picslaveold] ; master and slave PIC default mov dh,[picmasterold] ; values for this PC pop gs fs es ds ; restore segment registers jmp int31oknopop ; return ok, dont pop registers ; [fold] ] ; [fold] ] ;▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒ ; LOCK MEMORY FUNCTIONS ;▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒ ; [fold] [ ; So far all of these functions only clear the carry ;───────────────────────────────────────────────────────────────────────────── int310600: ; Lock Linear Region jmp int31ok ;───────────────────────────────────────────────────────────────────────────── int310601: ; Unlock Linear Region jmp int31ok ;───────────────────────────────────────────────────────────────────────────── int310602: ; Mark Real Mode Region as Pageable jmp int31ok ;───────────────────────────────────────────────────────────────────────────── int310603: ; Relock Real Mode Region jmp int31ok ;───────────────────────────────────────────────────────────────────────────── int310604: ; Get Page Size sub bx,bx mov cx,4096 jmp int31oksinoax ; [fold] ] ;▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒ ; DEMAND PAGING PERFORMANCE TUNING SERVICES ;▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒ ; [fold] [ ; So far all of these functions only clear the carry ;───────────────────────────────────────────────────────────────────────────── int310702: ; Mark Page as Demand Paging Candidate jmp int31ok ;───────────────────────────────────────────────────────────────────────────── int310703: ; Discard Page Contents jmp int31ok ; [fold] ] ;▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒ ; PMODE/DJ EXTENSIONS ;▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒ ; [fold] [ IF PMODEDJ_EXT EQ 1 ;═════════════════════════════════════════════════════════════════════════════ ; [fold] [ int310a00: ; PMODE/DJ DPMI extensions mov ds,[esp + 32 + 6] copy es,SELDS,ax do16to32 mov di,<off pmodedj_id> mov ecx,PMODEDJ_ID_SIZE repe cmps [BYTE PTR ds:esi],[BYTE PTR es:edi] dnop jnz int31fail8001 ; dont wanna talk to us mov [esp + 32 + 4],cs do16to32 mov <[WORD PTR esp + Dpmi_regs.edi]>,<off @@api> jmp int31ok ; [fold] ] ;----------------------------------------------------------------------------- ; [fold] [ @@api: ; extension entry stc DB 66h retf ; [fold] ] ENDIF ; [fold] ] ;▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒ ; COPROCESSOR FUNCTIONS ;▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒ ; [fold] [ ;───────────────────────────────────────────────────────────────────────────── ; [fold] [ int310e00: ; get coprocessor status mov al,[processortype] mov bl,[oldCR0L] cmp al,3 ; is it 386? jne short @@ok1 test bl,10h ; ET bit jnz short @@ok1 mov al,2 ; is 287 @@ok1: shl al,4 and bl,6 shl bl,1 or al,bl or al,[newEM_MP] sub ah,ah jmp int31okax ; [fold] ] ;───────────────────────────────────────────────────────────────────────────── ; [fold] [ int310e01: ; set coprocessor emulation mov eax,cr0 and al,0fbh ; clear bit 3 (EM) and bl,3 ; keep EM and MP bits mov [newEM_MP],bl shl bl,1 ; move to place and bl,4 ; clear MP or al,bl mov cr0,eax jmp int31ok ; [fold] ] ; [fold] ] ;▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒ ; VCPI EXTENDED MEMORY FUNCTIONS ;▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒ ; [fold] [ ;----------------------------------------------------------------------------- ; [fold] [ int310500vsiditoesi: ; convert handle SI:DI to ptr ESI pop bp ; pop return address test di,3 ; is handle (ptr) aligned on dword? jnz int31fail8023 ; if no, error 8023h shl esi,16 ; ESI = SI:DI mov si,di cmp esi,[pagetablefree] ; handle too low? jb int31fail8023 ; if yes, error 8023h cmp esi,[pagetabletop] ; handle too high? jae int31fail8023 ; if yes, error 8023h test [byte ptr coreseg:esi+1],2 ; is page first in allocated block? jz int31fail8023 ; if no, error 8023h jmp bp ; return ok ; [fold] ] ;----------------------------------------------------------------------------- ; [fold] [ int310500vbxcxtoebx: ; convert BX:CX bytes to EBX pages pop bp ; pop return address shl ebx,16 ; EBX = BX:CX mov bx,cx or ebx,ebx ; check for invalid value jz int31fail8021 ; if invalid value, error 8021h add ebx,0fffh ; convert EBX to page count shr ebx,12 jmp bp ; return ok ; [fold] ] ;----------------------------------------------------------------------------- ; [fold] [ int310500vpmalloc: ; allocate physical memory block mov edi,esi ; EDI = ESI, ptr to linear block start xor ebp,ebp ; EBP = running allocated page count @@int310500vpmallocl0: mov ax,0de04h ; VCPI allocate a page call [vcpi_service.ptr] or ah,ah ; got a page? jz short @@int310500vpmallocl0f0; if yes, go on cmp ebp,1 ; allocated any pages? jc short @@int310500vpmallocdone; if no, fail immediately or [byte ptr coreseg:edi-3],4 ; set last allocated page as last call int310500vfree ; free what was allocated stc ; carry set, failed jmp short @@int310500vpmallocdone ; go to done @@int310500vpmallocl0f0: and dh,0f0h ; clear 4 bits of page table entry mov dl,7 ; set page as user/writeable/present mov [coreseg:edi],edx ; store page in page table add edi,4 ; increment page table ptr inc ebp ; increment allocated page count cmp ebp,ebx ; allocated all needed pages? jb @@int310500vpmallocl0 ; if no, loop or [byte ptr coreseg:esi+1],2 ; set first allocated page as first or [byte ptr coreseg:edi-3],4 ; set last allocated page as last clc ; carry clear, success @@int310500vpmallocdone: mov eax,ebp ; EAX = number of pages allocated ret ; return ; [fold] ] ;----------------------------------------------------------------------------- ; [fold] [ int310500vlmalloc: ; check for linear memory block mov edi,[pagetablefree] ; EDI = search ptr in page table mov ecx,[pagetabletop] ; ECX = count of pages to search sub ecx,edi shr ecx,2 xor edx,edx ; EDX = largest linear block found xor eax,eax ; EAX = search unit, free entry (0) push ebx ; preserve EBX, memory requested @@int310500vlmallocl0: jecxz short @@int310500vlmallocdone ; if no more entries, done repne scas [dword ptr es:edi] ; search for first next free entry dnop jne short @@int310500vlmallocdone ; if no more free, go on mov ebp,ecx ; EBP = current count lea ebx,[edi-4] ; EBX = start of free block repe scas [dword ptr es:edi] ; search for end of free linear block dnop jne short @@int310500vlmallocl0f0 ; if previous entry not free, go on inc ebp ; previous entry free, extra one @@int310500vlmallocl0f0: sub ebp,ecx ; EBP = number of free pages in block cmp ebp,edx ; new block larger than last largest? jb @@int310500vlmallocl0 ; if no, loop mov esi,ebx ; ESI = ptr to largest block found mov edx,ebp ; size of new largest block found cmp ebp,[esp] ; block sufficient for memory request? jb @@int310500vlmallocl0 ; if no, loop @@int310500vlmallocdone: pop ebx ; restore EBX, memory requested ret ; return ; [fold] ] ;----------------------------------------------------------------------------- ; [fold] [ int310500vmalloc: ; allocate linear+physical mem block call int310500vlmalloc ; try to allocate linear memory block cmp edx,1 ; found ANY free linear area? jc short @@int310500vmallocdone ; if no, done cmp edx,ebx ; linear block enough for request? jb short @@int310500vmallocf0 ; if no, go to physical memory check call int310500vpmalloc ; try to allocate physical mem mov cl,1 ; error is not enough physical memory jmp short @@int310500vmallocdone; go to done @@int310500vmallocf0: mov ebx,edx ; only linear block size physical mem call int310500vpmalloc ; try to allocate physical memory jc short @@int310500vmallocfaillinear ; if failed, done call int310500vfree ; success, so must free block mov eax,ebx ; can allocate this much total memory stc ; carry set, failed @@int310500vmallocfaillinear: mov cl,0 ; error is not enough linear memory @@int310500vmallocdone: ret ; return ; [fold] ] ;----------------------------------------------------------------------------- ; [fold] [ int310500vfree: ; free linear+physical memory block mov edi,esi ; EDI = ESI, ptr to linear block start @@int310500vfreel0: xor ecx,ecx ; new page table entry is free (0) xchg ecx,[coreseg:edi] ; swap ECX with page table entry add edi,4 ; increment page table ptr mov edx,ecx ; EDX = page table entry and dx,0f000h ; mask off low 12 bits mov ax,0de05h ; VCPI free a page call [vcpi_service.ptr] test ch,4 ; last page of block? jz @@int310500vfreel0 ; if no, loop ret ; return ; [fold] ] ;───────────────────────────────────────────────────────────────────────────── ; [fold] [ int310500v: ; VCPI get free memory information push coreseg ; ES = core for VCPI malloc functions pop es mov ebx,0ffffffffh ; try to allocate an impossible amount call int310500vmalloc shl eax,12 ; returned EAX is highest possible jmp int310500xsetbuf ; put memory information in buffer ; [fold] ] ;───────────────────────────────────────────────────────────────────────────── ; [fold] [ int310501v: ; VCPI allocate memory block push coreseg ; ES=coreseg for VCPI malloc functions pop es call int310500vbxcxtoebx ; convert BX:CX bytes to EBX pages call int310500vmalloc ; try to allocate requested amount jnc short int310501vaddxnhandle ; if successful, go to done or cl,cl ; error is not enough linear memory? jz int31fail8012 ; if yes, error 8012h jmp int31fail8013 ; error is physical, error 8013h int310501vaddxnhandle: mov ecx,esi ; figure address of block from handle sub ecx,[pagetablebase] shl ecx,10 shld ebx,ecx,16 mov di,si ; SI:DI = ESI, handle shr esi,16 mov eax,[vcpi_cr3] ; reload CR3 to clear TLB mov cr3,eax jmp int31oksinoax ; return ok, with SI, DI, BX, CX ; [fold] ] ;───────────────────────────────────────────────────────────────────────────── ; [fold] [ int310502v: ; VCPI free memory block call int310500vsiditoesi ; convert handle SI:DI to ptr ESI call int310500vfree ; free memory block mov eax,[vcpi_cr3] ; reload CR3 to clear TLB mov cr3,eax jmp int31ok ; return ok ; [fold] ] ;───────────────────────────────────────────────────────────────────────────── ; [fold] [ int310503v: ; VCPI resize memory block push coreseg ; ES=coreseg for VCPI malloc functions pop es call int310500vbxcxtoebx ; convert BX:CX bytes to EBX pages call int310500vsiditoesi ; convert handle SI:DI to ptr ESI mov edi,esi ; EDI = ESI, ptr to linear block start xor ebp,ebp ; EBP = running block size in pages @@int310503vl0: add edi,4 ; increment page table ptr inc ebp ; increment block size test [byte ptr coreseg:edi-3],4 ; last page of block? jz @@int310503vl0 ; if no, loop sub ebx,ebp ; EBX = change in block size jz int310501vaddxnhandle ; if no change, done jc @@int310503vf0 ; if block made smaller, just free top mov ecx,[pagetabletop] ; ECX = count of pages to search sub ecx,edi shr ecx,2 mov edx,ecx ; EDX = current count xor eax,eax ; EAX = search unit, free entry (0) jecxz short @@int310503vf3 ; if no entries above, try below repe scas [dword ptr es:edi] ; check for free entries above block dnop je short @@int310503vf2 ; if previous entry free, go on dec edx ; previous entry not free, minus one @@int310503vf2: sub edx,ecx ; EDX = number of free pages in block cmp edx,ebx ; enough linear memory? jb short @@int310503vf3 ; if no, try below in linear memory push esi ; preserve start of block lea esi,[esi+ebp*4] ; ESI -> start of new block for alloc call int310500vpmalloc ; try to allocate physical memory mov edi,esi ; EDI -> start of new block pop esi ; restore start of old block jc int31fail8013 ; if alloc failed, error 8013h and [byte ptr coreseg:edi-3],0fbh ; clear last bit in old block end and [byte ptr coreseg:edi+1],0fdh ; clear first bit in new block start jmp int310501vaddxnhandle ; go to done @@int310503vf3: mov ecx,esi ; ECX = count of pages to search up sub ecx,[pagetablefree] shr ecx,2 or ecx,ecx ; any linear memory below? jz @@int310503vf1 ; if no, try to allocate push ebp ; preserve size of original block lea edi,[esi-4] ; EDI = ESI, ptr to linear block start mov ebp,ecx ; EBP = current count std ; search is up repe scas [dword ptr es:edi] ; check for free entries after block dnop cld je short @@int310503vf4 ; if previous entry free, go on dec ebp ; previous entry not free, minus one @@int310503vf4: sub ebp,ecx ; EBP = number of free pages in block lea eax,[ebp+edx] ; free size below + free size above pop ebp ; restore original block size cmp eax,ebx ; enough linear memory? jb @@int310503vf1 ; if no, try to allocate push esi ; preserve original block address sub ebx,edx ; EBX = number of pages needed below lea eax,[ebx*4] ; get base of block below sub esi,eax push edx ebp ; preserve some vars call int310500vpmalloc ; try to allocate physical memory pop ebp edx ; restore some vars mov edi,esi ; EDI -> base of block below pop esi ; restore base of original block jc int31fail8013 ; if alloc failed, error 8013h or edx,edx ; any pages needed above? jz short @@int310503vf6 ; if no, go on push esi edi ebp ; preserve some vars mov ebx,edx ; EBX = size of block below lea esi,[esi+ebp*4] ; ESI -> start of block above call int310500vpmalloc ; try to allocate physical memory pop ebp edi esi ; restore some vars jnc short @@int310503vf5 ; if allocated ok, go on mov esi,edi ; ESI -> allocated block below call int310500vfree ; free allocated block below jmp int31fail8013 ; fail, error 8013h @@int310503vf5: and [byte ptr coreseg:esi-3],0fbh ; clear last bit in below block end and [byte ptr coreseg:esi+ebp*4+1],0fdh ; clear first bit in above block start @@int310503vf6: and [byte ptr coreseg:edi+1],0fdh ; clear first bit in below block start and [byte ptr coreseg:esi+ebp*4-3],0fbh ; clear last bit in old block end push edi ; preserve new block start mov edx,edi ; EDX = base of move area lea ebx,[esi-4] ; EBX = current location in move area @@int310503vl1: mov edi,ebx ; set up to shift up a page mov esi,ebx mov ecx,ebp push ds ; save data selector push coreseg pop ds ; ds = core selector lods [dword ptr ds:esi] ; shift old pages a page down in table rep movs [dword ptr es:edi],[dword ptr ds:esi] stos [dword ptr es:edi] dnop ; 386 bug pop ds ; ds now data selector again sub ebx,4 ; decrement to next page to shift cmp ebx,edx ; more pages to shift? jae @@int310503vl1 ; if yes, loop pop esi ; restore new block start address jmp int310501vaddxnhandle ; go to done @@int310503vf1: add ebx,ebp ; restore EBX as requested size push esi ebp ; preserve some vars call int310500vlmalloc ; check for linear memory block pop ebp edi ; restore some vars cmp edx,ebx ; enough linear memory? jb int31fail8012 ; if no, error 8012h sub ebx,ebp ; EBX = extra pages needed push esi ; preserve for later copy lea esi,[esi+ebp*4] ; ESI -> start of extra space needed push edi ebp ; preserve some vars call int310500vpmalloc ; try to allocate physical memory pop ecx esi edi ; restore some vars jc int31fail8013 ; if not enough mem, error 8013h push edi esi ecx ; preserve, new and old block, size push ds push coreseg pop ds rep movs [dword ptr es:edi],[dword ptr ds:esi] ; copy old block pages dnop ; 386 bug pop ds and [byte ptr coreseg:edi-3],0fbh ; clear last bit in old block end and [byte ptr coreseg:edi+1],0fdh ; clear first bit in new block start pop ecx edi ; restore to clear old block xor eax,eax ; new page table entry is free (0) rep stos [dword ptr es:edi] ; clear old page table block dnop ; 386 bug pop esi ; restore new block address jmp int310501vaddxnhandle ; go to done @@int310503vf0: sub edi,4 ; decrement page table ptr xor edx,edx ; new page table entry is free (0) xchg edx,[coreseg:edi] ; swap EDX with page table entry and dx,0f000h ; mask off low 12 bits mov ax,0de05h ; VCPI free a page call [vcpi_service.ptr] inc ebx ; increment negative change counter jnz @@int310503vf0 ; if more pages to free, loop or [byte ptr coreseg:edi-3],4 ; set next page up as last of block jmp int310501vaddxnhandle ; go to done ; [fold] ] ;───────────────────────────────────────────────────────────────────────────── ; [fold] [ int31050av: ; VCPI get memory block size and base shrd ecx,esi,16 ; figure address of block from handle mov cx,di sub ecx,[pagetablebase] shl ecx,10 shld ebx,ecx,16 call int310500vsiditoesi ; convert handle SI:DI to ptr ESI xor edi,edi ; EDI = running page count @@int31050avl0: inc edi ; increment page count mov eax,[coreseg:esi] ; EAX = page table entry add esi,4 test ah,4 ; is this the last page of the block? jz short @@int31050avl0 ; if no, loop shl edi,12 ; convert EDI pages to bytes shld esi,edi,16 ; SI:DI = EDI, size in bytes jmp int31oksinoax ; return ok, with SI, DI, BX, CX ; [fold] ] ;───────────────────────────────────────────────────────────────────────────── ; [fold] [ int310800v: ; VCPI physical address mapping push coreseg pop es shl ebx,16 mov bx,cx cmp ebx,100000h ; below 1st MB? jb int31fail8021 ; DPMI says to fail then mov bx,si shl ebx,16 mov bx,di ; get size or ebx,ebx ; size 0? jz int31fail8021 ; if invalid value, error 8021h and ecx,0FFFh ; mask lower 12 bits of phys addr add ebx,ecx ; add page offset to size jc int31fail8021 add ebx,4095 jc int31fail8021 shr ebx,12 ; get # of pages push ecx ; save page offset call int310500vlmalloc ; allocate linear address space pop ebp cmp edx,ebx ; linear block enough for request? jb int31fail8012 ; if no, fail ; fill PTEs will correct values mov edi,esi ; edi = addr of PTE mov ax,[esp + Dpmi_regs.bx] shl eax,16 mov ax,[esp + Dpmi_regs.cx] ; get physical address and ah,0f0h ; clear 4 bits of page table entry mov al,17h ; user/writeable/present/PCD @@loop: mov [coreseg:edi],eax ; set page address add eax,4096 ; next page in real memory add edi,4 ; next PTE dec ebx jne short @@loop or [byte ptr coreseg:esi+1],2 ; set first allocated page as first or [byte ptr coreseg:edi-3],4 ; set last allocated page as last mov ecx,esi ; figure address of block from handle sub ecx,[pagetablebase] shl ecx,10 add ecx,ebp ; add page offset shld ebx,ecx,16 mov eax,[vcpi_cr3] ; reload CR3 to clear TLB mov cr3,eax mov si,[esp + Dpmi_regs.si] mov di,[esp + Dpmi_regs.di] jmp int31oksinoax ; [fold] ] ;───────────────────────────────────────────────────────────────────────────── ; [fold] [ int310801v: ; VCPI free physical address mapping shl ebx,16 mov bx,cx ; make linear address shr ebx,10 and bl,0FCh add ebx,[pagetablebase] ; EBX = start of PTE @@loop: sub eax,eax xchg eax,[coreseg:ebx] ; mark this PTE as free add ebx,4 test ah,4 ; last page? jz short @@loop ; if not, loop jmp int31ok ; [fold] ] ; [fold] ] ;▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒ ; XMS EXTENDED MEMORY FUNCTIONS ;▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒ ; [fold] [ ;----------------------------------------------------------------------------- ; [fold] [ int310500xsetbuf: ; Fills the memory information buffer of the caller mov es,[esp+24h] ; get ES:EDI buffer ptr from stack mov edi,[esp] stos [dword ptr es:edi] ; store block size in output buffer shr eax,12 ; convert from bytes to pages stos [dword ptr es:edi] ; store in output buffer max unlock stos [dword ptr es:edi] ; store in output buffer max locked dnop mov ecx,09h ; fill rest of buffer with 0ffffffffh mov eax,0ffffffffh rep stos [dword ptr es:edi] dnop jmp int31ok ; return ok ; [fold] ] ;----------------------------------------------------------------------------- ; [fold] [ int310500xcallxms: ; make a call to real mode XMS driver pop bp ; pop return address sub esp,32h ; stack space for register structure mov [esp+1ch],ax ; put AX in register structure mov [esp+10h],bx ; put BX in register structure mov [esp+18h],cx ; put CX in register structure mov [esp+14h],dx ; put DX in register structure mov [word ptr esp+20h],0 ; zero FLAGS in register structure mov [dword ptr esp+2eh],0 ; zero SS:SP in register structure mov eax,[xms_call.ptr] ; put XMS driver address in CS:IP in mov [esp+2ah],eax ; register structure push ss ; ES:EDI -> register structure pop es mov edi,esp xor cx,cx ; copy 0 words as stack parameters xor bh,bh ; doesnt really need to be here mov ax,301h ; call real mode FAR procedure int 31h mov ax,[esp+1ch] ; get AX from register structure mov bx,[esp+10h] ; get BX from register structure mov cx,[esp+18h] ; get CX from register structure mov dx,[esp+14h] ; get DX from register structure lea esp,[esp+32h] ; adjust ESP without changing FLAGS jc int31fail8010 ; if INT 31h failed, error 8010h jmp bp ; return ok ; [fold] ] ;----------------------------------------------------------------------------- ; [fold] [ int310500xbxcxtodx: ; convert BX:CX bytes to DX K pop bp ; pop return address mov dx,cx ; check for invalid value, BX=CX=0 or dx,bx jz int31fail8021 ; if invalid value, error 8021h add cx,1023+15 ; adjust for size in K and align adc bx,0 test bh,0fch ; memory request too high jnz int31fail8013 ; if yes, error 8013h shrd cx,bx,10 ; CX = memory in K mov dx,cx jmp bp ; return ok ; [fold] ] ;----------------------------------------------------------------------------- ; [fold] [ int310500xerror: ; XMS error, return with DPMI error cmp bl,0a0h ; out of memory? je int31fail8013 ; if yes, error 8013h cmp bl,0a1h ; handles exhausted? je int31fail8016 ; if yes, error 8016h cmp bl,0a2h ; invalid handle? je int31fail8023 ; if yes, error 8023h jmp int31fail8010 ; else, error 8010h ; [fold] ] ;───────────────────────────────────────────────────────────────────────────── ; [fold] [ int310500x: ; XMS get free memory information mov ah,8 ; get largest free memory block in K call int310500xcallxms movzx eax,ax ; EAX = free memory in bytes shl eax,10 sub eax,15 ; adjust by extra alignment size jnc int310500xsetbuf ; if no overflow, put info to buffer xor eax,eax ; overflow, so no memory available jmp int310500xsetbuf ; put memory information in buffer ; [fold] ] ;───────────────────────────────────────────────────────────────────────────── ; [fold] [ int310501x: ; XMS allocate memory block call int310500xbxcxtodx ; convert BX:CX bytes to DX K mov cx,dx ; preserve size of block in K mov ah,9 ; allocate DX K of XMS memory call int310500xcallxms or ax,ax ; error? jz int310500xerror ; if yes, convert XMS error to DPMI mov si,dx ; get DPMI handle from XMS handle int310501xgotmem: mov ah,0ch ; lock memory block call int310500xcallxms or ax,ax ; error? jnz short @@int310501xf0 ; if no, go on push bx ; yup, preserve error number mov ah,0ah ; free block causing lock error call int310500xcallxms pop bx ; restore error number jmp int310500xerror ; XMS error, return with DPMI error @@int310501xf0: mov di,cx ; low word of DPMI handle is size in K mov cx,bx ; XMS linear address to DPMI regs mov bx,dx add cx,0fh ; align linear address on paragraph adc bx,0 and cl,0f0h jmp int31oksinoax ; return ok, with SI, DI, BX, CX ; [fold] ] ;───────────────────────────────────────────────────────────────────────────── ; [fold] [ int310502x: ; XMS free memory block mov dx,si ; get XMS handle from DPMI handle mov ah,0dh ; unlock memory block call int310500xcallxms or ax,ax ; error? jz int310500xerror ; if XMS error, return with DPMI error mov ah,0ah ; free memory block call int310500xcallxms or ax,ax ; error? jz int310500xerror ; if yes, convert XMS error to DPMI jmp int31ok ; return ok ; [fold] ] ;───────────────────────────────────────────────────────────────────────────── ; [fold] [ int310503x: ; XMS resize memory block call int310500xbxcxtodx ; convert BX:CX bytes to DX K mov cx,dx ; preserve size of block in K mov dx,si ; get XMS handle from DPMI handle mov ah,0dh ; unlock memory block call int310500xcallxms or ax,ax ; error? jz int310500xerror ; if XMS error, return with DPMI error mov bx,cx ; BX = new size in K mov ah,0fh ; resize memory block call int310500xcallxms mov dx,si ; get XMS handle again or ax,ax ; error in resize? jnz int310501xgotmem ; if no, go to memory block code push bx ; yup, preserve error number mov ah,0ch ; lock memory block call int310500xcallxms pop bx ; restore error number jmp int310500xerror ; XMS error, return with DPMI error ; [fold] ] ;───────────────────────────────────────────────────────────────────────────── ; [fold] [ int31050ax: ; XMS get memory block size and base mov dx,si ; get XMS handle from DPMI handle mov si,di ; SI = size of block in K mov ah,0dh ; unlock memory block call int310500xcallxms or ax,ax ; error? jz int310500xerror ; if XMS error, return with DPMI error mov ah,0ch ; lock memory block call int310500xcallxms or ax,ax ; error? jz int310500xerror ; if XMS error, return with DPMI error xor di,di ; convert size in K to size in bytes shrd di,si,6 shr si,6 mov cx,bx ; XMS linear address to DPMI regs mov bx,dx mov ax,cx ; figure out alignment stub dec ax and ax,0fh xor al,0fh sub di,ax ; subtract alignment stub from size sbb si,0 add cx,0fh ; align linear address on paragraph adc bx,0 and cl,0f0h jmp int31oksinoax ; return ok, with SI, DI, BX, CX ; [fold] ] ;───────────────────────────────────────────────────────────────────────────── ; [fold] [ int310800xr: ; physical address mapping (both XMS and raw) shl ebx,16 mov bx,cx cmp ebx,100000h ; below 1st MB? jb int31fail8021 ; DPMI says to fail then or si,di jz int31fail8021 ; size is zero jmp int31ok ; physical and linear address is the same ; [fold] ] ;───────────────────────────────────────────────────────────────────────────── int310801xr: ; free physical address mapping (both XMS and raw) jmp int31ok ; physical and linear address is the same ; [fold] ] ;▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒ ; RAW EXTENDED MEMORY FUNCTIONS ;▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒ ; [fold] [ ;----------------------------------------------------------------------------- ; [fold] [ int310500rnomem: ; no free extended memory present xor eax,eax ; 0 available extended memory jmp int310500xsetbuf ; put memory information in buffer ; [fold] ] ;----------------------------------------------------------------------------- ; [fold] [ int310500rbxcxtoebx: ; convert BX:CX bytes to EBX bytes pop bp ; pop return address shl ebx,16 ; EBX = BX:CX mov bx,cx or ebx,ebx ; check for invalid value jz int31fail8021 ; if invalid value, error 8021h add ebx,0fh ; align EBX on paragraph and bl,0f0h jmp bp ; return ok ; [fold] ] ;----------------------------------------------------------------------------- ; [fold] [ int310500rfindmcb: ; find MCB for handle SI:DI pop bp ; pop return address shl esi,16 ; ESI = handle SI:DI = address of MCB mov si,di mov edi,[rawextmemtop] ; EDI -> first memory control block @@int310500rfindmcbl0: cmp edi,esi ; found MCB? jne short @@int310500rfindmcbl0f0 ; if no, keep looking cmp [byte ptr coreseg:edi-4],0 ; memory block free? je int31fail8023 ; if yes, error 8023h jmp bp ; return ok, found MCB @@int310500rfindmcbl0f0: mov edi,[coreseg:edi-12] ; EDI -> next memory control block or edi,edi ; is there another MCB? jnz @@int310500rfindmcbl0 ; if yes, loop jmp int31fail8023 ; fail, error 8023h ; [fold] ] ;----------------------------------------------------------------------------- ; [fold] [ int310500radjustused: ; adjust INT 15h extended memory used mov eax,[rawextmemtop] ; EAX -> first memory control block @@int310500radjustusedl0: cmp [dword ptr coreseg:eax-12],0 ; last memory control block? jz short @@int310500radjustusedf0 ; if yes, go to set new used K mov eax,[coreseg:eax-12] ; EAX -> next memory control block jmp @@int310500radjustusedl0 ; loop @@int310500radjustusedf0: cmp [byte ptr coreseg:eax-4],0 ; memory block free? je short @@int310500radjustusedf1 ; if no, go on sub eax,[coreseg:eax-16] ; used, adjust by size of block @@int310500radjustusedf1: sub eax,10h ; adjust by size of MCB and eax,0fffffc00h ; align on K sub eax,[rawextmemtop] ; size of extended memory used neg eax shr eax,10 ; convert from bytes to K mov [rawextmemused],ax ; adjust INT 15h extended memory used @@int310500radjustuseddone: ret ; return ; [fold] ] ;----------------------------------------------------------------------------- ; [fold] [ int310500rlinkmcb: ; link memory blocks at ESI and EDI mov eax,[coreseg:esi-16] ; combine two block sizes add eax,10h add [coreseg:edi-16],eax ; add size of next block to this one mov ecx,[coreseg:esi-12] ; copy next MCB field mov [coreseg:edi-12],ecx jecxz short @@int310500rlinkmcbf0 ; if no next MCB, done mov [coreseg:ecx-8],edi ; set prev MCB in next MCB to this MCB @@int310500rlinkmcbf0: ret ; return ; [fold] ] ;───────────────────────────────────────────────────────────────────────────── ; [fold] [ int310500r: ; raw get free memory information mov edi,[rawextmemtop] ; EDI -> first memory control block xor eax,eax ; running highest free memory block @@int310500rl0: cmp [byte ptr coreseg:edi-4],0 ; is block free? jne short @@int310500rl0f0 ; if no, loop mov ebx,[coreseg:edi-16] ; EBX = size of block cmp eax,ebx ; last free block larger? ja short @@int310500rl0f0 ; if yes, loop mov eax,ebx ; found larger block, new largest @@int310500rl0f0: mov edi,[coreseg:edi-12] ; EDI -> next memory control block or edi,edi ; is there another MCB? jnz @@int310500rl0 ; if yes, loop jmp int310500xsetbuf ; put memory information in buffer ; [fold] ] ;───────────────────────────────────────────────────────────────────────────── ; [fold] [ int310501r: ; raw allocate memory block call int310500rbxcxtoebx ; convert BX:CX bytes to EBX bytes mov edi,[rawextmemtop] ; EDI -> first memory control block @@int310501rl0: cmp [byte ptr coreseg:edi-4],0 ; is block free? je short @@int310501rl0f2 ; if yes, check block @@int310501rl0f0: mov edi,[coreseg:edi-12] ; EDI -> next memory control block or edi,edi ; is there another MCB? jnz @@int310501rl0 ; if yes, loop jmp int31fail8013 ; fail, error 8013h @@int310501rl0f2: lea ecx,[coreseg:edi-10h] ; ECX -> possible new MCB sub ecx,ebx mov eax,[coreseg:edi-16] ; EAX = size of block sub eax,ebx ; enough free memory in block? jc short @@int310501rl0f0 ; if no, loop jz short @@int310501rl0f1 ; if exactly same size, continue sub eax,10h ; adjust for size of new created MCB mov [coreseg:ecx-16],eax ; put size of new block in new MCB mov eax,ecx ; set next MCB in old MCB as new one xchg [coreseg:edi-12],eax ; copy next MCB from old to new MCB mov [coreseg:ecx-12],eax or eax,eax ; is there a next MCB? jz short @@int310501rl0f3 ; if no, go on mov [coreseg:eax-8],ecx ; set prev MCB in next MCB to new MCB @@int310501rl0f3: mov [coreseg:ecx-8],edi ; set prev MCB in new MCB as old one mov [byte ptr coreseg:ecx-4],0 ; set new MCB as free mov [coreseg:edi-16],ebx ; set size of allocated block @@int310501rl0f1: mov [byte ptr coreseg:edi-4],1 ; set block as allocated int310501raddxnhandle: shld ebx,ecx,16 ; BX:CX = ECX, address of block shld esi,edi,16 ; SI:DI = EDI, handle (address of MCB) call int310500radjustused ; adjust INT 15h extended memory used jmp int31oksinoax ; return ok, with SI, DI, BX, CX ; [fold] ] ;───────────────────────────────────────────────────────────────────────────── ; [fold] [ int310502r: ; raw free memory block call int310500rfindmcb ; find MCB for handle SI:DI mov [byte ptr coreseg:edi-4],0 ; set this memory block as free mov esi,[coreseg:edi-12] ; ESI -> next memory control block or esi,esi ; is there next MCB? jz short @@int310502rf0 ; if no, go on cmp [byte ptr coreseg:esi-4],0 ; is next memory block free? jne short @@int310502rf0 ; if no, go on call int310500rlinkmcb ; link two memory blocks @@int310502rf0: mov esi,[coreseg:edi-8] ; ESI -> previous memory control block or esi,esi ; is there previous MCB? jz short @@int310502rf1 ; if no, go on cmp [byte ptr coreseg:esi-4],0 ; is previous memory block free? jne short @@int310502rf1 ; if no, go on xchg esi,edi ; change mcb order for function call int310500rlinkmcb ; link two memory blocks @@int310502rf1: call int310500radjustused ; adjust INT 15h extended memory used jmp int31ok ; return ok ; [fold] ] ;───────────────────────────────────────────────────────────────────────────── ; [fold] [ int310503r: ; raw resize memory block call int310500rbxcxtoebx ; convert BX:CX bytes to EBX bytes mov edx,ebx ; EDX = size of new block call int310500rfindmcb ; find MCB for handle SI:DI copy ds,SELCORE,ax ; for easier block copy copy es,ds,ax ; ES = DS for possible block copy sub ebx,[esi-16] ; EBX = change in block size jz @@int310503rf0 ; if no change, done jc @@int310503rf1 ; if block made smaller, just free top xor eax,eax ; running memory counter mov ecx,[esi-12] ; ECX -> next MCB jecxz short @@int310503rf4 ; if no next MCB, check previous MCB cmp [byte ptr ecx-4],0 ; next MCB free? jne short @@int310503rf4 ; if not, check previous MCB mov eax,[ecx-16] ; EAX = amount of free memory in block add eax,10h ; including memory control block @@int310503rf4: mov ecx,[esi-8] ; ECX -> previous MCB jecxz short @@int310503rf5 ; if no previous MCB, check memory cmp [byte ptr ecx-4],0 ; previous MCB free? jne short @@int310503rf5 ; if not, check memory add eax,[ecx-16] ; add amount of free memory in block add eax,10h ; including memory control block @@int310503rf5: cmp eax,ebx ; enough to resize within area jb @@int310503rf3 ; if no, try to allocate or ecx,ecx ; is there a previous MCB? jz @@int310503rf6 ; if no, resize to next cmp [byte ptr ecx-4],0 ; previous MCB free? jne short @@int310503rf6 ; if not, resize to next mov ebp,[ecx-16] ; EBP = size of previous block, try to add ebp,10h ; resize within previous block sub ebp,ebx ; EBP = prev block size - needed size jbe short @@int310503rf7 ; if prev block too small, go on mov edi,ecx ; EDI -> new MCB for new memory block sub edi,ebp ; resize will fit entirely lea eax,[ebp-10h] ; EAX = new size of free block mov [ecx-16],eax ; store mew free size in prev MCB mov [edi-16],edx ; store new size in new MCB mov [ecx-12],edi ; set next MCB in prev MCB to new MCB mov [edi-8],ecx ; set prev MCB in new MCB to prev MCB mov [byte ptr edi-4],1 ; set new MCB as used mov ecx,[esi-12] ; copy next MCB field mov [edi-12],ecx or ecx,ecx ; is there a next MCB jz @@int310503rf0 ; if no, go to block readjust mov [ecx-8],edi ; set prev MCB in next MCB to new MCB jmp @@int310503rf0 ; go to block readjust @@int310503rf7: mov edi,ecx ; EDI -> new MCB for new memory block lea eax,[edx+ebp] ; EAX = size of new block mov [edi-16],eax ; store mew free size in new MCB mov [byte ptr edi-4],1 ; set new MCB as used mov ecx,[esi-12] ; copy next MCB field mov [edi-12],ecx jecxz short @@int310503rf8 ; if no next MCB, go on mov [ecx-8],edi ; set prev MCB in next MCB to new MCB @@int310503rf8: add ebp,ebx ; EBP = size of block just acquired sub ebx,ebp ; EBX = new size still needed jz @@int310503rf0 ; if no more space needed, done mov esi,edi ; ESI -> new MCB @@int310503rf6: mov edi,[esi-12] ; EDI -> next MCB mov ecx,[edi-12] ; copy next MCB field mov [esi-12],ecx jecxz short @@int310503rf9 ; if no next MCB, go on mov [ecx-8],esi ; set prev MCB in next MCB to this MCB @@int310503rf9: mov eax,[edi-16] ; EAX = size of next memory block add eax,10h sub edi,eax ; EDI -> start of next memory block sub eax,ebx ; EAX = amount of free space left mov ecx,[esi-16] ; ECX = old size of this memory block mov [esi-16],edx ; store new size in this MCB mov [byte ptr esi-4],1 ; set this MCB as used sub esi,ecx ; ESI -> start of this memory block sub esi,10h shr ecx,2 ; copy this memory block down in mem rep movs [dword ptr es:edi],[dword ptr ds:esi] dnop add esi,10h ; adjust ESI to top MCB mov edi,esi ; EDI -> top MCB mov ebx,eax ; EBX = negative of space free at top neg ebx jz @@int310503rf0 ; in no space free, go to done jmp short @@int310503rf1 ; set new MCBs for moved block @@int310503rf3: mov ebp,edi ; preserve old block MCB address sub edx,ebx ; EDX = size of old block mov bx,[esp+16] ; BX:CX = new block size from stack mov cx,[esp+24] mov ax,501h ; try to allocate new block int 31h jc int31failax ; if could not, fail with error AX shrd eax,esi,16 ; EAX -> new block MCB mov ax,di shrd edi,ebx,16 ; EDI -> start of new block mov di,cx lea esi,[ebp-10h] ; ESI -> start of old block sub esi,edx mov ecx,edx ; copy memory from old block to new shr ecx,2 rep movs [dword ptr es:edi],[dword ptr ds:esi] dnop mov edx,eax ; EDX -> new block MCB shld esi,ebp,16 ; SI:DI = handle of old block mov di,bp mov ax,0502h ; free old block int 31h mov edi,edx ; EDI -> new block MCB for done jmp short @@int310503rf0 ; go to done @@int310503rf1: lea edi,[esi+ebx] ; EDI -> new MCB for new memory block lea eax,[ebx+10h] ; EAX = size of freed block neg eax mov [esi-16],eax ; store freed size in old MCB mov [edi-16],edx ; store new size in new MCB mov ecx,[esi-12] ; copy next MCB field mov [edi-12],ecx jecxz short @@int310503rf2 ; if no next MCB, go on mov [ecx-8],edi ; set prev MCB in next MCB to new MCB @@int310503rf2: mov [esi-12],edi ; set next MCB in old MCB as new MCB mov [edi-8],esi ; set prev MCB in new MCB as old MCB mov [byte ptr edi-4],1 ; set new MCB as used mov [byte ptr esi-4],0 ; set old MCB as free mov ecx,[esi-8] ; ECX -> prev MCB of old MCB jecxz short @@int310503rf0 ; if no prev MCB, done cmp [byte ptr ecx-4],0 ; is previous MCB free? jne short @@int310503rf0 ; if no, dont link push edi ; preserve new MCB mov edi,ecx ; top MCB = prev MCB for link function call int310500rlinkmcb ; link two memory blocks pop edi ; restore new MCB @@int310503rf0: mov ecx,[edi-16] ; ECX = base address of new block neg ecx lea ecx,[ecx+edi-10h] push SELDS pop ds ; restore old DS jmp int310501raddxnhandle ; return address and handle ; [fold] ] ;───────────────────────────────────────────────────────────────────────────── ; [fold] [ int31050ar: ; raw get memory block size and base call int310500rfindmcb ; find MCB for handle SI:DI mov edi,[coreseg:esi-16] ; EDI = size of memory block lea ecx,[coreseg:esi-10h] ; get base address of memory block sub ecx,edi shld ebx,ecx,16 ; BX:CX = ECX, address of block shld esi,edi,16 ; SI:DI = EDI, size of memory block jmp int31oksinoax ; return ok, with SI, DI, BX, CX ; [fold] ] ; [fold] ] ENDS END ; [fold] 142