1 2 %if 0 3 4 Example of using MMX in DPMI protected mode 5 6 Copyright (C) 1995-2003 Paul Vojta 7 Copyright (C) 2008-2023 C. Masloch 8 9 %endif 10 11 %include "lmacros3.mac" 1 <1> [list -] 14 <2> [list -] 14 <1> [list -] 12 13 numdef 32BITCODE, 0 14 numdef DUMPA32, 0 15 numdef DUMPOFFSET, 1 16 numdef DUMPES, 1 17 18 19 cpu 386 20 org 100h 21 bits 16 22 start: 23 00000000 58 pop ax ; get word saved on stack for COM files 24 00000001 89E3 mov bx, sp 25 00000003 83C30F add bx, 15 26 00000006 C1EB04 shr bx, 4 27 00000009 7503 jnz .smallstack 28 0000000B BB0010 mov bx, 1000h ; it was a full 64 KiB stack 29 .smallstack: 30 0000000E B44A mov ah, 4Ah ; free unused memory 31 00000010 CD21 int 21h 32 00000012 31C0 xor ax, ax 33 00000014 87062C00 xchg ax, word [2Ch] 34 00000018 8EC0 mov es, ax 35 0000001A B449 mov ah, 49h 36 0000001C CD21 int 21h ; free environment if any 37 38 0000001E B88716 mov ax, 1687h 39 00000021 CD2F int 2Fh 40 00000023 85C0 test ax, ax ; DPMI host installed? 41 00000025 7526 jnz nohost 42 00000027 06 push es ; save DPMI entry address 43 00000028 57 push di 44 00000029 85F6 test si, si ; host requires client-specific DOS memory? 45 0000002B 740A jz .nomemneeded ; no --> 46 0000002D 89F3 mov bx, si 47 0000002F B448 mov ah, 48h 48 00000031 CD21 int 21h ; allocate memory 49 00000033 721D jc nomemory 50 00000035 8EC0 mov es, ax 51 .nomemneeded: 52 00000037 BE[9D03] mov si, msg.debuginfo 53 0000003A E85E01 call printstring 54 0000003D CC int3 55 0000003E 89E5 mov bp, sp 56 00000040 B80100 mov ax, 0001h ; start a 32-bit client 57 00000043 FF5E00 call far [bp] ; initial switch to protected-mode 58 00000046 7315 jnc initsuccessful 59 initfailed: 60 00000048 BE[7F03] mov si, msg.initfailed 61 0000004B EB08 jmp short rmerror 62 nohost: 63 0000004D BE[3203] mov si, msg.nohost 64 00000050 EB03 jmp short rmerror 65 nomemory: 66 00000052 BE[4C03] mov si, msg.nomemory 67 rmerror: 68 00000055 E84301 call printstring 69 00000058 B8FF4C mov ax, 4CFFh 70 0000005B CD21 int 21h 71 72 initsuccessful: 73 initsuccessful_ofs equ (initsuccessful-$$+100h) 74 ; now in protected mode 75 %if _32BITCODE 76 mov bx, cs 77 mov cx, cs 78 lar cx, cx 79 shr cx, 8 80 or ch, 40h ; make a 32-bit cs 81 mov ax, 9 82 int 31h 83 ; now in 32-bit PM 84 bits 32 85 now32bit: 86 now32bit_ofs equ (now32bit-$$+100h) 87 %endif 88 0000005D 8C06[3003] mov word [ data.pspsel ], es 89 00000061 1E push ds 90 00000062 07 pop es 91 92 %if _32BITCODE 93 mov esi, msg.welcome 94 call printstring 95 %endif 96 97 ; If we're in 32-bit PM then CPU is at least a 386. 98 99 detect_mmx: 100 ; Copied from init.asm, debugging messages 101 ; and machine variable access removed. 102 00000063 89E3 mov bx, sp ; save current stack pointer to align 103 00000065 83E4FC and sp, ~3 ; align stack to avoid AC fault 104 00000068 669C pushfd ; push original EFLAGS 105 0000006A 6658 pop eax ; get original EFLAGS 106 0000006C 6689C1 mov ecx, eax ; save original EFLAGS in ECX (including IF) 107 108 0000006F 663500000400 xor eax, 40000h ; flip AC bit in EFLAGS 109 00000075 25FFFD and ax, ~0200h ; clear IF 110 00000078 6650 push eax ; put new EFLAGS value on stack 111 0000007A 669D popfd ; replace EFLAGS value; DI 112 0000007C 669C pushfd ; get new EFLAGS 113 0000007E 6658 pop eax ; store new EFLAGS value in EAX 114 00000080 89C8 mov ax, cx ; ignore low bits (including IF) 115 00000082 6639C8 cmp eax, ecx 116 00000085 7416 je .cpudone_stack_eax_equals_ecx ; if 80386 --> 117 118 ; Intel486 DX CPU, Intel487 SX NDP, and Intel486 SX CPU check. 119 ; Checking for ability to set/clear ID flag (bit 21) in EFLAGS 120 ; which indicates the presence of a processor with the ability 121 ; to use the CPUID instruction. 122 00000087 6689C8 mov eax, ecx ; get original EFLAGS 123 0000008A 663500002000 xor eax, 200000h ; flip ID bit in EFLAGS 124 00000090 25FFFD and ax, ~0200h ; clear IF 125 00000093 6650 push eax ; save new EFLAGS value on stack 126 00000095 669D popfd ; replace current EFLAGS value; DI 127 00000097 669C pushfd ; get new EFLAGS 128 00000099 6658 pop eax ; store new EFLAGS in EAX 129 0000009B 89C8 mov ax, cx ; ignore low bits (including IF) 130 131 .cpudone_stack_eax_equals_ecx: 132 0000009D 6651 push ecx 133 0000009F 669D popfd ; restore AC,ID bits and IF in EFLAGS (86 Mode) 134 000000A1 89DC mov sp, bx ; restore sp 135 136 000000A3 6639C8 cmp eax, ecx ; check if it's changed 137 000000A6 741B je .cpudone ; if it's a 486 (can't toggle ID bit) --> 138 139 ; Execute CPUID instruction. 140 subcpu 486 ; NASM (at least 2.10rc1) handles cpuid itself as a 141 ; 586+ instruction, but we know better. So this 142 ; part is declared for 486 compatibility, and only 143 ; the cpuid instructions are emitted with 586 144 ; compatibility to appease NASM. 145 000000A8 6631C0 xor eax, eax ; set up input for CPUID instruction 146 [cpu 586] 147 000000AB 0FA2 cpuid 148 __CPU__ 149 000000AD 6683F801 cmp eax, byte 1 150 000000B1 7210 jb .cpudone ; if 1 is not a valid input value for CPUID 151 000000B3 6631C0 xor eax, eax ; otherwise, run CPUID with eax = 1 152 000000B6 6640 inc eax 153 [cpu 586] 154 000000B8 0FA2 cpuid 155 __CPU__ 156 000000BA 66F7C200008000 test edx, 80_0000h 157 000000C1 750E jnz @F 158 .cpudone: 159 subcpureset 160 000000C3 66BE[08040000] mov esi, msg.nommx 161 000000C9 E8CF00 call printstring 162 000000CC B8FF4C mov ax, 4CFFh 163 000000CF CD21 int 21h 164 165 @@: 166 cpu 586 167 havemmx: 168 havemmx_ofs equ (havemmx-$$+100h) 169 000000D1 9BDBE3 finit 170 000000D4 0F6F06[2803] movq mm0, qword [testvalue] 171 000000D9 6631C0 xor eax, eax 172 000000DC 6650 push eax 173 000000DE 6650 push eax 174 000000E0 660FB7DC movzx ebx, sp 175 000000E4 670F7F03 movq qword [ebx], mm0 176 177 000000E8 66BB[28020000] mov ebx, dump1 178 %if _DUMPES 179 %define ESPREFIX es: 180 %else 181 %define ESPREFIX 182 %endif 183 %if _DUMPA32 184 %if _DUMPOFFSET 185 o32 fnsave [dword ESPREFIX dump1] 186 o32 fldenv [dword ESPREFIX dump1] 187 %else 188 o32 fnsave [ESPREFIX ebx] 189 o32 fldenv [ESPREFIX ebx] 190 %endif 191 %else 192 %if _DUMPOFFSET 193 000000EE 2666DD36[2802] o32 fnsave [word ESPREFIX dump1] 194 000000F4 2666D926[2802] o32 fldenv [word ESPREFIX dump1] 195 %else 196 o32 fnsave [ESPREFIX bx] 197 o32 fldenv [ESPREFIX bx] 198 %endif 199 %endif 200 000000FA E8A400 call disp_dump 201 202 000000FD 66BB[A8020000] mov ebx, dump2 203 %if _DUMPA32 204 %if _DUMPOFFSET 205 o32 fnsave [dword ESPREFIX dump2] 206 o32 fldenv [dword ESPREFIX dump2] 207 %else 208 o32 fnsave [ESPREFIX ebx] 209 o32 fldenv [ESPREFIX ebx] 210 %endif 211 %else 212 %if _DUMPOFFSET 213 00000103 2666DD36[A802] o32 fnsave [word ESPREFIX dump2] 214 00000109 2666D926[A802] o32 fldenv [word ESPREFIX dump2] 215 %else 216 o32 fnsave [ESPREFIX bx] 217 o32 fldenv [ESPREFIX bx] 218 %endif 219 %endif 220 0000010F E88F00 call disp_dump 221 222 00000112 66BE[24040000] mov esi, msg.firstread 223 00000118 E88000 call printstring 224 0000011B 6658 pop eax 225 0000011D 665A pop edx 226 0000011F E8C400 call disp_edxeax_hex 227 00000122 6609C2 or edx, eax 228 00000125 6652 push edx 229 00000127 66BE[D5040000] mov esi, msg.linebreak 230 0000012D E86B00 call printstring 231 00000130 665A pop edx 232 00000132 6685D2 test edx, edx 233 00000135 750E jnz @F 234 00000137 66BE[4F040000] mov esi, msg.firstzero 235 0000013D E85B00 call printstring 236 00000140 B8FF4C mov ax, 4CFFh 237 00000143 CD21 int 21h 238 239 @@: 240 00000145 6631C0 xor eax, eax 241 00000148 6650 push eax 242 0000014A 6650 push eax 243 0000014C 660FB7DC movzx ebx, sp 244 00000150 670F7F03 movq qword [ebx], mm0 245 00000154 66BE[39040000] mov esi, msg.secondread 246 0000015A E83E00 call printstring 247 0000015D 6658 pop eax 248 0000015F 665A pop edx 249 00000161 E88200 call disp_edxeax_hex 250 00000164 6609C2 or edx, eax 251 00000167 6652 push edx 252 00000169 66BE[D5040000] mov esi, msg.linebreak 253 0000016F E82900 call printstring 254 00000172 665A pop edx 255 00000174 6685D2 test edx, edx 256 00000177 750E jnz @F 257 00000179 66BE[7D040000] mov esi, msg.secondzero 258 0000017F E81900 call printstring 259 00000182 B8FF4C mov ax, 4CFFh 260 00000185 CD21 int 21h 261 262 @@: 263 00000187 66BE[AC040000] mov esi, msg.mmxgood 264 0000018D E80B00 call printstring 265 266 00000190 B8004C mov ax, 4C00h 267 00000193 CD21 int 21h ; normal client exit (terminates DOS process too) 268 269 ; Print a string with simple instructions. Don't use 270 ; pointers or instructions depending on the default operation 271 ; size, this is called in both 16- and 32-bit modes. 272 printstring.next: 273 00000195 88C2 mov dl, al 274 00000197 B402 mov ah, 2 275 00000199 CD21 int 21h 276 printstring: 277 0000019B AC lodsb 278 0000019C 84C0 test al, al 279 0000019E 75F5 jnz .next 280 000001A0 C3 retn 281 282 283 disp_dump: 284 000001A1 6631D2 xor edx, edx 285 000001A4 66B908000000 mov ecx, 128 / 16 286 .loop_line: 287 000001AA 6692 xchg eax, edx 288 000001AC E84900 call disp_ax_hex 289 000001AF 6692 xchg eax, edx 290 000001B1 B020 mov al, 32 291 000001B3 E86200 call disp_al 292 000001B6 E85F00 call disp_al 293 000001B9 6651 push ecx 294 000001BB B110 mov cl, 16 295 .loop_byte: 296 000001BD 678A0413 mov al, byte [ebx + edx] 297 000001C1 E83B00 call disp_al_hex 298 000001C4 B020 mov al, 32 299 000001C6 E84F00 call disp_al 300 000001C9 6642 inc edx 301 000001CB E2F0 loop .loop_byte 302 000001CD 6659 pop ecx 303 000001CF B00D mov al, 13 304 000001D1 E84400 call disp_al 305 000001D4 B00A mov al, 10 306 000001D6 E83F00 call disp_al 307 000001D9 E2CF loop .loop_line 308 000001DB B00D mov al, 13 309 000001DD E83800 call disp_al 310 000001E0 B00A mov al, 10 311 000001E2 E83300 call disp_al 312 000001E5 C3 retn 313 314 disp_edxeax_hex: 315 000001E6 6692 xchg eax, edx 316 000001E8 E80200 call disp_eax_hex 317 000001EB 6692 xchg eax, edx 318 319 disp_eax_hex: 320 000001ED 66C1C010 rol eax, 16 321 000001F1 E80400 call disp_ax_hex 322 000001F4 66C1C010 rol eax, 16 323 324 disp_ax_hex: 325 000001F8 86C4 xchg al, ah 326 000001FA E80200 call disp_al_hex 327 000001FD 86C4 xchg al, ah 328 329 disp_al_hex: 330 000001FF C0C004 rol al, 4 331 00000202 E80300 call disp_nybble_hex 332 00000205 C0C004 rol al, 4 333 334 disp_nybble_hex: 335 00000208 50 push ax 336 00000209 240F and al, 0Fh 337 0000020B 3C0A cmp al, 10 338 0000020D 7202 jb .decit 339 0000020F 0407 add al, 'A' - ('0' + 10) 340 .decit: 341 00000211 0430 add al, '0' 342 00000213 E80200 call disp_al 343 00000216 58 pop ax 344 00000217 C3 retn 345 346 disp_al: 347 00000218 50 push ax 348 00000219 52 push dx 349 0000021A 92 xchg dx, ax 350 0000021B B402 mov ah, 02h 351 0000021D CD21 int 21h 352 0000021F 5A pop dx 353 00000220 58 pop ax 354 00000221 C3 retn 355 356 357 00000222 00 align 8, db 0 358 00000228 00 dump1: times 128 db 0 359 000002A8 CC dump2: times 128 db 0CCh 360 361 align 8, db 0 362 00000328 4226000038110000 testvalue: dq 1138_0000_2642h 363 364 align 2, db 0 365 data: 366 00000330 0000 .pspsel: dw 0 367 368 msg: 369 00000332 4E6F2044504D492068- .nohost: asciz "No DPMI host installed.",13,10 369 0000033B 6F737420696E737461- 369 00000344 6C6C65642E0D0A00 370 0000034C 4E6F7420656E6F7567- .nomemory: asciz "Not enough DOS memory for client initialization.",13,10 370 00000355 6820444F53206D656D- 370 0000035E 6F727920666F722063- 370 00000367 6C69656E7420696E69- 370 00000370 7469616C697A617469- 370 00000379 6F6E2E0D0A00 371 0000037F 44504D4920696E6974- .initfailed: asciz "DPMI initialization failed.",13,10 371 00000388 69616C697A6174696F- 371 00000391 6E206661696C65642E- 371 0000039A 0D0A00 372 0000039D 50726F746563746564- .debuginfo: db "Protected mode breakpoint at ",_4digitshex(initsuccessful_ofs),"h.",13,10 372 000003A6 206D6F646520627265- 372 000003AF 616B706F696E742061- 372 000003B8 742030313544682E0D- 372 000003C1 0A 373 %if _32BITCODE 374 db "32-bit code segment breakpoint at ",_4digitshex(now32bit_ofs),"h.",13,10 375 %endif 376 000003C2 48617665204D4D5820- db "Have MMX breakpoint at ",_4digitshex(havemmx_ofs),"h.",13,10 376 000003CB 627265616B706F696E- 376 000003D4 742061742030314431- 376 000003DD 682E0D0A 377 000003E1 0D0A00 asciz 13,10 378 000003E4 57656C636F6D652069- .welcome: asciz "Welcome in 32-bit protected mode.",13,10 378 000003ED 6E2033322D62697420- 378 000003F6 70726F746563746564- 378 000003FF 206D6F64652E0D0A00 379 00000408 4572726F723A204D4D- .nommx: asciz "Error: MMX not supported.",13,10 379 00000411 58206E6F7420737570- 379 0000041A 706F727465642E0D0A- 379 00000423 00 380 00000424 466972737420726561- .firstread: asciz "First read returned",9 380 0000042D 642072657475726E65- 380 00000436 640900 381 00000439 5365636F6E64207265- .secondread: asciz "Second read returned",9 381 00000442 61642072657475726E- 381 0000044B 65640900 382 0000044F 4572726F723A204D4D- .firstzero: asciz "Error: MMX read returns zero on first read.",13,10 382 00000458 582072656164207265- 382 00000461 7475726E73207A6572- 382 0000046A 6F206F6E2066697273- 382 00000473 7420726561642E0D0A- 382 0000047C 00 383 0000047D 4572726F723A204D4D- .secondzero: asciz "Error: MMX read returns zero on second read.",13,10 383 00000486 582072656164207265- 383 0000048F 7475726E73207A6572- 383 00000498 6F206F6E207365636F- 383 000004A1 6E6420726561642E0D- 383 000004AA 0A00 384 000004AC 4D4D582073696E676C- .mmxgood: asciz "MMX single-register R/W seems to work.",13,10 384 000004B5 652D72656769737465- 384 000004BE 7220522F5720736565- 384 000004C7 6D7320746F20776F72- 384 000004D0 6B2E0D0A00 385 000004D5 0D0A00 .linebreak: asciz 13,10