Skip to content

Commit bbaf6b8

Browse files
use unreal-mode with interrupts enabled for block moves; optional NMI aware variant added;
1 parent 9f2c491 commit bbaf6b8

3 files changed

Lines changed: 161 additions & 37 deletions

File tree

HimemX.asm

Lines changed: 156 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -66,23 +66,29 @@
6666

6767
;--- assembly time parameters
6868

69-
VERSIONSTR equ <'3.39'>
70-
DRIVER_VER equ 300h+39
69+
VERSIONSTR equ <'3.40'>
70+
DRIVER_VER equ 300h+40
7171
INTERFACE_VER equ 300h
7272

7373
ifndef NUMHANDLES
7474
NUMHANDLES equ 48 ;std 48, default number of handles
7575
endif
7676
MAXHANDLES equ 128 ;std 128, max number of handles
7777
ALLOWDISABLEA20 equ 1 ;std 1, 1=allow to disable A20
78-
BLOCKSIZE equ 2000h ;std 2000h, block size moved to/from ext. memory
79-
USEUNREAL equ 1 ;std 1, 1=use "unreal" mode for EMB copy
78+
BLOCKSIZE equ 2000h ;std 2000h, block size moved to/from ext. memory (max 16-bits!)
79+
ifndef USEUNREAL
80+
USEUNREAL equ 2 ;std 2, 0=use pmode; 1=set/reset "unreal" mode; 2=set unreal if GPF occurs
81+
endif
82+
DISABLEIRQS equ USEUNREAL ne 2 ;0=don't disable interrupts during block move
8083
PREF66LGDT equ 0 ;std 0, 1=use 66h prefix for LGDT
8184
?LOG equ 0 ;std 0, 1=enable /LOG option
8285
?TESTMEM equ 0 ;std 0, 1=enable /TESTMEM:ON|OFF option
8386
ifndef ?ALTSTRAT
8487
?ALTSTRAT equ 0 ;std 0, 1=use alternate strategie for (re)alloc emb
8588
endif
89+
ifndef ?NMIOPT
90+
?NMIOPT equ 0 ;std 0, 1=support /NMI cmdline option
91+
endif
8692
?MERGE0HDL equ 1 ;std 0, 1=try to merge even if handle to free has size 0
8793
?ALLOCDX0 equ 1 ;std 1, 1=return DX=0 if alloc fails
8894
;--- change for v3.39: std now 1
@@ -160,6 +166,30 @@ ifdef _DEBUG
160166
endif
161167
endm
162168

169+
@NMI_OFF macro savereg
170+
if ?NMIOPT
171+
ifnb <savereg>
172+
push savereg
173+
endif
174+
call nmi_off
175+
ifnb <savereg>
176+
pop savereg
177+
endif
178+
endif
179+
endm
180+
181+
@NMI_ON macro savereg
182+
if ?NMIOPT
183+
ifnb <savereg>
184+
push savereg
185+
endif
186+
call nmi_on
187+
ifnb <savereg>
188+
pop savereg
189+
endif
190+
endif
191+
endm
192+
163193
@display macro value
164194
echo value
165195
endm
@@ -313,6 +343,9 @@ szX DB '/X', 00H
313343
szMETHOD DB '/METHOD:', 00H
314344
szMAX DB '/MAX=', 00H
315345
szMaximum DB 'Maximum XMS: %luK', 0aH, 00H
346+
if ?NMIOPT
347+
szNMI DB '/NMI', 00H
348+
endif
316349
szHMAMIN DB '/HMAMIN=', 00H
317350
szMinimum DB 'Minimum HMA that has to be requested: %uK', 0aH, 00H
318351
szHMAMAX DB 'HimemX: HMAMIN must be <= 63, corrected', 0aH, 00H
@@ -384,6 +417,9 @@ if ?TESTMEM
384417
db " /TESTMEM:ON|OFF Performs or skips an extended memory test (def: OFF)",10
385418
endif
386419
db " /VERBOSE Gives extra information",10
420+
if ?NMIOPT
421+
db " /NMI Make HimemX NMI aware",10
422+
endif
387423
db " /NOABOVE16 Do not use INT 15h function E801h to detect >64M",10
388424
db " /X Do not use INT 15h function E820h to detect >64M",10
389425
db " /X2MAX32 Limit XMS 2.0 free/avail. memory report to 32M-1K",10
@@ -560,16 +596,31 @@ exit_set_reset_carry:
560596

561597
do_move:
562598
pushf
599+
@NMI_OFF ax
563600
call test_a20
564601
jz isdisabled
565602
call cs:[old_int15]
603+
@NMI_ON ax
566604
call enable_a20 ; preserves flags
567605
jmp exit_set_reset_carry
568606
isdisabled:
569607
call cs:[old_int15]
608+
@NMI_ON ax
570609
call disable_a20 ; preserves flags
571610
jmp exit_set_reset_carry
572611

612+
if ?NMIOPT
613+
nmi_off::
614+
mov al,80h
615+
jmp @F
616+
nmi_on::
617+
mov al,0
618+
@@:
619+
out 70h,al
620+
in al,71h
621+
ret
622+
endif
623+
573624
int15_handler endp
574625

575626
;******************************************************************************
@@ -584,7 +635,6 @@ int2f_handler proc
584635
db 0EAh
585636
old_int2f dd 0 ; old INT 2fh vector
586637

587-
588638
@@maybe_my2f:
589639
cmp al,00h ; is it "Installation Check"?
590640
je @@get_driver_installed
@@ -1298,8 +1348,15 @@ endif
12981348
@@move_ok_to_start:
12991349
SMSW AX ; don't use priviledged "mov eax,cr0"!
13001350
test al,1 ; are we already in PM?
1351+
if DISABLEIRQS eq 0
1352+
jnz copy_pm
1353+
call rmcopy ; no need to loop in this case
1354+
jmp @@xms_exit_copy
1355+
copy_pm:
1356+
else
13011357
mov bx,offset rmcopy ; no, switch to pm yourself
13021358
jz @F
1359+
endif
13031360
push ss ; set ES for int 15h, ah=87h call
13041361
pop es
13051362
mov bx,offset pmcopy ; yes, use INT 15h, ah=87h
@@ -1367,21 +1424,26 @@ endif
13671424
; EDI = dst linear adress
13681425
; ECX = length (hiword cleared)
13691426

1370-
; 2 strategies are implemented. The first does the move in protected-mode,
1371-
; the latter activates "unreal" mode and does the move there.
1372-
; After the last transfer "unreal" mode is exited. Interrupts occuring
1373-
; during the "interrupt window" will run in "unreal" mode as well, but
1374-
; this shouldn't hurt.
1427+
; 3 strategies are implemented:
1428+
; 1) the block copy is done in protected-mode
1429+
; 2) the block copy is done in "unreal" mode, which is explicitely
1430+
; enabled and disabled. After the last transfer "unreal" mode is exited.
1431+
; Interrupts occuring during the "interrupt window" will run in "unreal"
1432+
; mode as well, but this shouldn't hurt.
1433+
; 3) An interrupt handler for INT 0Dh is set temporarily, then the copy op
1434+
; starts, assuming "unreal" mode is active. If assumtion is wrong, an
1435+
; exception will occur, and the interrupt handler will enable "unreal".
13751436

13761437
rmcopy:
13771438

1378-
ife USEUNREAL
1439+
if USEUNREAL eq 0
13791440

1441+
@NMI_OFF
13801442
pushf
13811443
cli ; no interrupts when doing protected mode
1382-
if PREF66LGDT
1444+
if PREF66LGDT
13831445
db 66h ; load full 32bit base
1384-
endif
1446+
endif
13851447
lgdt fword ptr cs:[gdt32]; load GDTR (use CS prefix here)
13861448
mov eax,cr0
13871449
inc ax ; set PE bit
@@ -1392,10 +1454,11 @@ endif
13921454
mov ds,dx
13931455
mov es,dx
13941456

1395-
shr ecx,2 ; get number of DWORDS to move
1396-
rep movs @dword [edi],[esi]
1457+
; shr ecx,2 ; get number of DWORDS to move
1458+
shr cx,2 ; hiword(ecx) is 0
1459+
rep movsd [edi],[esi]
13971460
adc cx,cx
1398-
rep movs @word [edi],[esi] ; move a trailing WORD
1461+
rep movsw [edi],[esi] ; move a trailing WORD
13991462

14001463
db 67h ; don't remove - some 80386s were buggy
14011464
nop ; don't remove - some 80386s were buggy
@@ -1410,20 +1473,20 @@ endif
14101473
clc
14111474
ret
14121475

1413-
else
1476+
elseif USEUNREAL eq 1
14141477

1415-
if 0
14161478
pushf
14171479
cli ; no interrupts during the block move
14181480
pushf
14191481
call set_ureal ; every time since the mode might have been
14201482
xor dx,dx ; exited by an interrupt routine.
14211483
mov ds,dx
14221484
mov es,dx
1423-
shr ecx,2 ; get number of DWORDS to move
1424-
rep movs @dword [edi],[esi]
1485+
; shr ecx,2 ; get number of DWORDS to move
1486+
shr cx,2 ; hiword(ecx) is 0
1487+
rep movsd [edi],[esi]
14251488
adc cx,cx
1426-
rep movs @word [edi],[esi] ; move a trailing WORD
1489+
rep movsw [edi],[esi] ; move a trailing WORD
14271490
db 67h ; don't remove - some 80386s were buggy
14281491
nop ; don't remove - some 80386s were buggy
14291492
popf
@@ -1437,9 +1500,10 @@ else
14371500
set_ureal:
14381501
mov dx,data32sel
14391502
reset_ureal:
1440-
if PREF66LGDT
1503+
@NMI_OFF
1504+
if PREF66LGDT
14411505
db 66h ; load full 32bit base
1442-
endif
1506+
endif
14431507
lgdt fword ptr cs:[gdt32]; load GDTR (use CS prefix here)
14441508
mov eax,cr0
14451509
inc ax ; set PE bit
@@ -1452,33 +1516,79 @@ endif
14521516
mov ds,dx
14531517
mov es,dx
14541518
mov cr0,eax
1519+
@NMI_ON
14551520
ret
1521+
1522+
else ; USEUNREAL eq 2
1523+
1524+
mov ax,cs
1525+
shl eax,16
1526+
if DISABLEIRQS eq 0 ;checks if interrupts may be ON
1527+
mov dx, offset myint0d_2 ; NO check for IRQ 5 in INT 0Dh
1528+
pushf
1529+
pop ax
1530+
test ah,2 ; IF set?
1531+
jz ifdone ; no check if interrupts disabled
1532+
mov al,0Bh
1533+
out 20h,al
1534+
jmp @F
1535+
@@:
1536+
in al,20h ; get ISS
1537+
test al,20h; IRQ 5 in service?
1538+
jnz ifdone
1539+
mov dx, offset myint0d ; check for IRQ 5 in INT 0Dh
1540+
ifdone:
1541+
mov ax, dx
14561542
else
1457-
;--- set int 0dh, then just start to copy.
1458-
;--- if int 0dh is called, an exception occured, since IRQs are disabled.
1459-
;--- then set unreal mode inside int 0dh code.
1543+
mov ax, offset myint0d
1544+
endif
1545+
1546+
;--- set int 0dh, then start copying.
1547+
;--- if int 0dh is triggered, check PIC to see if it's an IRQ;
1548+
;--- if no, it's an exception and unreal mode is activated.
1549+
14601550
xor dx,dx
1461-
mov ax,cs
14621551
mov ds,dx
14631552
mov es,dx
1553+
if DISABLEIRQS
14641554
pushf
1465-
shl eax,16
1466-
mov ax,offset myint0d
1467-
shr ecx,2 ; get number of DWORDS to move
14681555
cli
1556+
endif
1557+
shr ecx,2 ; get number of DWORDS to move
14691558
xchg eax,ds:[13*4]
1470-
rep movs @dword [edi],[esi]
1559+
rep movsd [edi],[esi]
14711560
adc cx,cx
1472-
rep movs @word [edi],[esi] ; move a trailing WORD
1561+
rep movsw [edi],[esi] ; move a trailing WORD
14731562
db 67h ; don't remove - some 80386s were buggy
14741563
nop ; don't remove - some 80386s were buggy
14751564
mov ds:[13*4],eax ; restore int 0dh
1565+
if DISABLEIRQS
14761566
popf
1567+
endif
14771568
ret
14781569
myint0d:
1570+
if DISABLEIRQS eq 0
1571+
push ax
1572+
;--- if IRQs aren't disabled, check if an IRQ 5 is "in service";
1573+
;--- if no, assume it's an exception;
1574+
;--- this is the MS Himem way of doing things; however,
1575+
;--- XMS block moves inside an IRQ 5 handler may not work then!
1576+
mov al,0Bh
1577+
out 20h,al
1578+
jmp @F
1579+
@@:
1580+
in al,20h
1581+
test al,20h ;IRQ 5 in service?
1582+
pop ax
1583+
jz myint0d_2
1584+
push eax ;assume eax holds old int 0Dh vector
1585+
retf
1586+
myint0d_2:
1587+
endif
1588+
push eax
14791589
push ds
14801590
push es
1481-
push eax
1591+
@NMI_OFF
14821592
lgdt fword ptr cs:[gdt32]; load GDTR (use CS prefix here)
14831593
mov eax,cr0
14841594
inc ax ; set PE bit
@@ -1490,15 +1600,14 @@ myint0d:
14901600
mov ds,dx
14911601
mov es,dx
14921602
mov cr0,eax
1493-
pop eax
1603+
@NMI_ON
14941604
pop es
14951605
pop ds
1606+
pop eax
14961607
iret
1497-
endif
14981608

14991609
endif
15001610

1501-
15021611
;------------------------------------------------------------------------
15031612
; cpu is in v86-mode, use int15, ah=87 to copy things around
15041613

@@ -3161,6 +3270,17 @@ no_numhandles:
31613270
mov _x_option,1
31623271
@@:
31633272

3273+
if ?NMIOPT
3274+
;--- option /NMI
3275+
push offset szNMI
3276+
call _FindCommand
3277+
or ax,ax
3278+
jne @F
3279+
mov byte ptr [nmi_off],0C3h
3280+
mov byte ptr [nmi_on],0C3h
3281+
@@:
3282+
endif
3283+
31643284
;--- option /METHOD
31653285
push offset szMETHOD
31663286
call _FindCommand
@@ -3431,7 +3551,6 @@ e820_done:
34313551
ret
34323552
geti15mem endp
34333553

3434-
34353554
;--- driver init. this proc should be last
34363555
;--- since it initializes the handle table
34373556
;--- ds:di = request_ptr

History.txt

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,10 @@
11

22
History
33

4+
24.02.2026, v3.40:
5+
- optional cmdline option /NMI added to make HimemX NMI aware.
6+
- if unreal-mode is on, block copies are done with interrupts enabled.
7+
48
12.03.2025, v3.39:
59
- function ah=0Eh (get handle information): returns now error A2h (invalid
610
handle) if size > 65535 kB. This is MS Himem compatible. Previously the

Make.bat

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,3 +3,4 @@ rem JWasm used to create HimemX.exe & HimemX2.exe
33
if not exist "Release\NUL" mkdir Release
44
jwasm.exe -nologo -mz -Sg -Sn -Fl=Release\HimemX.LST -Fo=Release\HimemX.exe HimemX.asm
55
jwasm.exe -nologo -mz -Sg -Sn -D?ALTSTRAT=1 -Fl=Release\HimemX2.LST -Fo=Release\HimemX2.exe HimemX.asm
6+
jwasm.exe -nologo -mz -Sg -Sn -D?NMIOPT=1 -Fl=Release\HimemXn.LST -Fo=Release\HimemXn.exe HimemX.asm

0 commit comments

Comments
 (0)