%if 0 Example of using Protected Mode XMS entrypoint Public Domain %endif struc XMSMOVE xmsmCount: resd 1 ; The count must be even. xmsmSourceHandle: resw 1 xmsmSourceAddress: resd 1 xmsmDestHandle: resw 1 xmsmDestAddress: resd 1 ; The destination and source may overlap only if a ; forward move would suffice to implement the ; operation without corrupting the data. (That is, ; the source starts above the destination. The XMS ; specification gets this detail wrong.) ; There is an error code for invalid overlap, but ; it is unclear whether this condition is detected ; properly by all implementations. endstruc ;%include "lmacros1.mac" %define _4digitshex(h) ((((h)/1000h)% 10h)+'0' +(('A'-'9'-1)*((((h)/1000h)% 10h)/0Ah))), \ ((((h)/100h)% 10h)+'0' +(('A'-'9'-1)*((((h)/100h)% 10h)/0Ah))), \ ((((h)/10h)% 10h)+'0' +(('A'-'9'-1)*((((h)/10h)% 10h)/0Ah))), \ (((h)% 10h)+'0' +(('A'-'9'-1)*(((h)% 10h)/0Ah))) ; ASCIZ string ; ; %1+ = Optional string %imacro asciz 0-1+.nolist %if %0 >= 1 db %1 %endif db 0 %endmacro BIGBIT equ 1 DEFAULTBIT equ 2 OPERANDSIZE equ 4 COMPARE equ 8 cpu 386 org 100h bits 16 start: pop ax ; get word saved on stack for COM files mov bx, sp add bx, 15 shr bx, 4 jnz .smallstack mov bx, 1000h ; it was a full 64 KiB stack .smallstack: mov ah, 4Ah ; free unused memory int 21h xor ax, ax xchg ax, word [2Ch] mov es, ax mov ah, 49h int 21h ; free environment if any mov dx, OPERANDSIZE ; default: small stack, 16-bit cs, o32 mov si, 81h loop: lodsb mov dh, BIGBIT cmp al, 'B' je .or cmp al, 'b' je .clr mov dh, DEFAULTBIT cmp al, 'D' je .or cmp al, 'd' je .clr mov dh, OPERANDSIZE cmp al, 'O' je .or cmp al, 'o' je .clr mov dh, COMPARE cmp al, 'C' je .or cmp al, 'c' je .clr cmp al, 13 je .end cmp al, 9 je loop cmp al, 32 je loop cmp al, ',' je loop mov si, msg.errorcmdline jmp rmerror .or: or dl, dh jmp loop .clr: not dh and dl, dh jmp loop .end: mov byte [data.flags], dl mov ax, 1687h int 2Fh test ax, ax ; DPMI host installed? jnz nohost push es ; save DPMI entry address push di test si, si ; host requires client-specific DOS memory? jz .nomemneeded ; no --> mov bx, si mov ah, 48h int 21h ; allocate memory jc nomemory mov es, ax .nomemneeded: mov word [ data.base ], cs mov word [xm + xmsmDestAddress + 2], cs mov si, msg.debuginfo call printstring int3 mov bp, sp mov ax, 0001h ; start a 32-bit client call far [bp] ; initial switch to protected-mode jnc initsuccessful initfailed: mov si, msg.initfailed jmp short rmerror nohost: mov si, msg.nohost jmp short rmerror nomemory: mov si, msg.nomemory rmerror: call printstring mov ax, 4CFFh int 21h initsuccessful: initsuccessful_ofs equ (initsuccessful-$$+100h) ; now in protected mode mov ax, 4300h int 2Fh cmp al, 80h jne noxms16 xor ax, ax mov es, ax mov ax, 4310h int 2Fh mov ax, es test ax, ax jz noxms16 mov word [data.call16 + 2], ax mov word [data.call32 + 4], ax mov word [data.call16], bx mov dword [data.call32], ebx mov word [ data.pspsel ], es push ds pop es xor eax, eax mov cx, 1 int 31h ; allocate 1 selector jc noselector xchg ebx, eax ; bx = our selector xor ecx, ecx xor edx, edx ; cx:dx = base to set (0) mov ax, 7 int 31h ; set selector base jc noselector LIMIT equ (1024 + 64) * 1024 - 1 mov cx, LIMIT >> 16 mov dx, LIMIT & 0FFFFh mov ax, 8 ; set selector limit int 31h jc noselector lar ecx, ebx shr ecx, 8 or ch, 40h ; set D bit mov ax, 9 int 31h jc noselector mov word [data.flatsel], bx test byte [data.flags], BIGBIT jz skipbig movzx eax, word [ data.base ] shl eax, 4 movzx esp, sp add eax, esp mov ss, bx mov esp, eax ; set stack skipbig: test byte [data.flags], DEFAULTBIT jnz go32 go16: mov esi, xm mov ah, 00h test byte [data.flags], OPERANDSIZE jnz .callo32 .callo16: call far word [data.call16] mov ah, 0Bh call far word [data.call16] jmp .after .callo32: call far dword [data.call32] mov ah, 0Bh call far dword [data.call32] .after: dec ax jnz failxms16 test byte [data.flags], COMPARE jz .success mov es, word [data.flatsel] xor di, di mov si, dest mov cx, dest.size repe cmpsb je .success mov si, msg.mismatch jmp pmerror .success: mov si, msg.success call printstring mov ax, 4C00h int 21h ; normal client exit (terminates DOS process too) go32: mov bx, cs mov cx, cs lar cx, cx shr cx, 8 or ch, 40h ; make a 32-bit cs mov ax, 9 int 31h ; now in 32-bit PM bits 32 mov esi, xm mov ah, 00h test byte [data.flags], OPERANDSIZE jnz .callo32 .callo16: call far word [data.call16] mov ah, 0Bh call far word [data.call16] jmp .after .callo32: call far dword [data.call32] mov ah, 0Bh call far dword [data.call32] .after: dec ax jnz failxms32 test byte [data.flags], COMPARE jz .success mov es, word [data.flatsel] xor edi, edi mov esi, dest mov ecx, dest.size repe cmpsb je .success mov esi, msg.mismatch jmp pmerror .success: mov esi, msg.success call printstring mov ax, 4C00h int 21h ; normal client exit (terminates DOS process too) failxms32: mov esi, msg.failxms jmp pmerror noselector: mov esi, msg.noselector pmerror: call printstring mov ax, 4CFFh int 21h ; Print a string with simple instructions. Don't use ; pointers or instructions depending on the default operation ; size, this is called in both 16- and 32-bit modes. printstring.next: mov dl, al mov ah, 2 int 21h printstring: lodsb test al, al jnz .next retn bits 16 noxms16: mov si, msg.noxms jmp pmerror failxms16: mov si, msg.failxms jmp pmerror align 8 data: .call32: dq 0 .call16: dd 0 .base: dw 0 .flatsel: dw 0 .pspsel: dw 0 .flags: db 0 align 4 xm: istruc XMSMOVE at xmsmCount, dd dest.size at xmsmSourceHandle, dw 0 at xmsmSourceAddress, dd 0 at xmsmDestHandle, dw 0 at xmsmDestAddress, dw dest iend dest: .size equ 16 times .size nop msg: .errorcmdline: asciz "FAIL. Command line error.",13,10 .nohost: asciz "FAIL. No DPMI host installed.",13,10 .nomemory: asciz "FAIL. Not enough DOS memory for client initialization.",13,10 .initfailed: asciz "FAIL. DPMI initialization failed.",13,10 .noselector: asciz "FAIL. Failed to allocate or write selector.",13,10 .noxms: asciz "FAIL. No XMS entrypoint found.",13,10 .failxms: asciz "FAIL. XMS move call failed.",13,10 .mismatch: asciz "FAIL. Destination data mismatch.",13,10 .debuginfo: db "Protected mode breakpoint at ",_4digitshex(initsuccessful_ofs),"h.",13,10 asciz 13,10 .success: asciz "SUCCESS.",13,10