forked from Baron-von-Riedesel/HimemSX
-
Notifications
You must be signed in to change notification settings - Fork 0
/
HimemSX.asm
3929 lines (3400 loc) · 85.9 KB
/
HimemSX.asm
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
;--- HimemSX, XMM able to manage up to 1 TB memory.
;--- assembly time parameters
DRIVER_VER equ 300h+52h
VERSIONSTR equ <'3.52'>
INTERFACE_VER equ 350h
lf equ 10
ifndef NUMHANDLES
NUMHANDLES equ 48 ;std 48, default number of handles
endif
MAXHANDLES equ 128 ;std 128, max. number of handles
ALLOWDISABLEA20 equ 1 ;std 1, 1=allow to disable A20
BLOCKSIZE equ 2000h ;std 2000h, block size moved to/from ext. memory (max is 65535!)
USEUNREAL equ 1 ;std 1, 1=use "unreal" mode for EMB copy
PREF66LGDT equ 0 ;std 0, 1=use 66h prefix for LGDT
?LOG equ 0 ;std 0, 1=enable /LOG option
?TESTMEM equ 0 ;std 0, 1=enable /TESTMEM:ON|OFF option
ifndef ?ALTSTRAT
?ALTSTRAT equ 0 ;std 0, 1=use alternate strategy for (re)alloc emb
endif
?MERGE0HDL equ 1 ;std 1, 1=try to merge even if handle to free has size 0
?HINF_MSCOMP equ 1 ;std 1, 1=func. 0Eh (get handle info) MS Himem compatible
?PD110000 equ 0 ;std 0, 1=page dir at 110000h, 0=page dir at end of first i15 block
?ALLOCDX0 equ 1 ;std 1, 1=return DX=0 if alloc fails
ifdef _DEBUG
?CATCHEXC equ 1 ;catch exceptions in protected-mode
else
?CATCHEXC equ 0
endif
?RESTDSESREGS equ 1 ;restore segment registers from unreal mode
?RESTCSREG equ 1 ;restore CS seg after sx pmode - shouldn't be necessary, but apparently is...
if ?RESTDSESREGS or ?CATCHEXC
;--- if DS+ES is to be restored to 64kB before leaving protected-mode,
;--- set page 0-3FFFFFh to RW since GDT is written then [accessed bit] and
;--- CR0 WP bit may be set!
PF_PAGE0 equ 80h + 2 + 1 ;set 4MB page + RW + Present
else
PF_PAGE0 equ 80h + 1 ;set 4MB page + Present
endif
;MAXFREEKB equ 0FBC0h
MAXFREEKB equ 0FFFFh ;std FFFFh, xms v2.0 max ext. memory
;--- constants
CPUID1_PSE36 equ 17
XMS_START equ 1024+64 ; XMS starts at 1088k after HMA
CMD_INIT equ 0 ; init command (used when installed)
;--- DOS device driver status codes used
STATUS_OK equ 0100h ; driver is initialized and ok
STATUS_BAD equ 8103h ; driver couldn't be installed
VDISK_IDSTR equ "VDISK"
VDISK_IDLEN equ 5
VDISK_IDOFS equ 13h
;--- A20 switch methods (must match order in "methods" table)
A20_KBC equ 0
A20_PS2 equ 1
A20_BIOS equ 2
A20_ALWAYSON equ 3
A20_FAST equ 4
A20_PORT92 equ 5
;--- XMS error codes
XMS_NOT_IMPLEMENTED equ 80h
XMS_VDISK_DETECTED equ 81h
XMS_A20_FAILURE equ 82h
XMS_DRIVER_FAILURE equ 8eh
XMS_DRIVER_FATAL equ 8fh
XMS_HMA_NOT_THERE equ 90h
XMS_HMA_IN_USE equ 91h
XMS_HMAREQ_TOO_SMALL equ 92h
XMS_HMA_NOT_USED equ 93h
XMS_A20_STILL_ENABLED equ 94h
XMS_ALL_MEM_ALLOCATED equ 0a0h
XMS_NO_HANDLE_LEFT equ 0a1h
XMS_INVALID_HANDLE equ 0a2h
XMS_INVALID_SOURCE_HANDLE equ 0a3h
XMS_INVALID_SOURCE_OFFSET equ 0a4h
XMS_INVALID_DESTINATION_HANDLE equ 0a5h
XMS_INVALID_DESTINATION_OFFSET equ 0a6h
XMS_INVALID_LENGTH equ 0a7h
XMS_INVALID_OVERLAP equ 0a8h
XMS_PARITY_ERROR equ 0a9h
XMS_BLOCK_NOT_LOCKED equ 0aah
XMS_BLOCK_LOCKED equ 0abh
XMS_LOCK_COUNT_OVERFLOW equ 0ach
XMS_LOCK_FAILED equ 0adh
XMS_ONLY_SMALLER_UMB equ 0b0h
XMS_NO_UMB_AVAILABLE equ 0b1h
XMS_UMB_SEGMENT_NR_INVALID equ 0b2h
option proc:private
option casemap:none
@byte equ <byte ptr>
@word equ <word ptr>
@dword equ <dword ptr>
@DbgOutS macro string
if 0;def _DEBUG
call printstring
db string
db 0
endif
endm
@display macro value
echo value
endm
;--- structures
;--- cpu GDT descriptor
desc struct
limit dw ? ; segment limit
base00_15 dw ? ; low word of base address
base16_23 db ? ; high byte of base address
db ? ; 93h = std ring 0 read/write segment
attr db ? ; attributes, limit 16-19
base24_31 db ?
desc ends
;--- DOS device driver request header
request_hdr struct
req_size db ? ; number of bytes stored
unit_id db ? ; unit ID code
cmd db ? ; command code
status dw ? ; status word
rsvd db 8 dup (?) ; reserved
request_hdr ends
;--- DOS device driver request for INIT
init_strc struct
init_hdr db size request_hdr dup (?)
units db ? ; number of supported units
end_addr dd ? ; end address of resident part
cmd_line dd ? ; address of command line
init_strc ends
;--- XMS_HANDLE is a documented structure, size 10 bytes
XMS_HANDLE struct
xh_flags db ? ; see below
xh_locks db ? ; lock count
xh_baseK dd ? ; base address in kbytes
xh_sizeK dd ? ; size in kbytes
XMS_HANDLE ends
;--- defined values for XMS_HANDLE.flags
XMSF_FREE equ 1 ;describes a free block
XMSF_USED equ 2 ;describes a used block
XMSF_INPOOL equ 4 ;describes a free handle
;--- XMS handle table (documented structure, size 8 bytes)
XMS_HANDLETABLE struct
xht_sig DB ? ; identifier byte?, 1 for MS-DOS HIMEM, 0FDH for us
xht_sizeof DB ? ; size of handle descriptor (xms_handle)
xht_numhandles DW ? ; number of handles
xht_pArray DD ? ; pointer to XMS handles array
XMS_HANDLETABLE ends
;--- structure for XMS AH=0Bh (documented structure)
xms_move struct
len dd ? ; block length in bytes
src_handle dw ? ; source handle
src_offset dd ? ; offset into source
dest_handle dw ? ; destination handle
dest_offset dd ? ; offset into destination
xms_move ends
;--- int 15h, ax=E820h (documented)
SMAP equ 534d4150h
E820MAP struct
baselow dd ?
basehigh dd ?
lenlow dd ?
lenhigh dd ?
type_ dd ?
E820MAP ends
IRETS struct
wIP dw ?
wCS dw ?
bFlags db ?
bFlags2 db ?
IRETS ends
;--- segment definitions
.SEQ ;place segments in the order defined here
_RTEXT segment dword public 'CODE' ; resident code+data
_RTEXT ends
_TEXT segment word public 'CODE' ; nonresident code
_TEXT ends
_DATA segment word public 'DATA' ; nonresident data
_DATA ends
_STACK segment STACK 'STACK' ;1 kB stack
db 1024 dup(?)
_stacktop label byte
_STACK ends
;--- use the TINY model
DGROUP group _RTEXT,_TEXT,_DATA,_STACK
.386P ; 386 instructions + privileged opcodes
;--- nonresident data
_DATA segment
;--- variables
request_ptr DD 0 ; pointer to request header
xms_max DD 4095*1024; value /MAX= parameter
xms_smax DD 1023*4096*1024; value /SUPERMAX= parameter
dwMaxHigh dd -1 ; mask for upper memory address limit
_xms_num_handles DW NUMHANDLES ;value /NUMHANDLES= parameter
_method DB -1 ; value /METHOD: parameter
_startup_verbose DB 00H ; value /VERBOSE parameter
if ?LOG
_xms_logging_enabled DB 00H ; value /LOG parameter
endif
hma_exists db 0
;--- constants
szStartup DB 'HimemSX v', VERSIONSTR, ' [', @CatStr(!"%@Date!"), ']', lf
db 'Portions (c) Till Gerken & tom ehlert.', lf, 0
if ?TESTMEM
szTESTMEMOFF DB '/TESTMEM:OFF', 0
endif
szVerbose DB '/V', 0
if ?LOG
szLOG DB '/LOG', 0
endif
szINTERFACE DB 'Interface : XMS v3.5 80686 1TB', lf, 0
szNUMHANDLES DB '/NUMHANDLES=', 0
szSelNumHandles DB 'No of XMS handles: %u', lf, 0
szNumHandlesLim1 DB 'HimemSX: NUMHANDLES must be >= 8, corrected', lf, 0
szNumHandlesLim2 DB 'HimemSX: NUMHANDLES must be <= ',@CatStr(!",%MAXHANDLES,!"),', corrected', lf, 0
szX2MAX32 DB '/X2MAX32', 0
szMETHOD DB '/METHOD:', 0
szMAX DB '/MAX=', 0
szSUPERMAX DB '/SUPERMAX=', 0
szMaximum DB 'Maximum extended memory: %luK', lf, 0
szHMAMIN DB '/HMAMIN=', 0
szMinimum DB 'Minimum HMA that has to be requested: %uK', lf, 0
szHMAMAX DB 'HimemSX: HMAMIN must be <= 63, corrected', lf, 0
szPageDir DB 'Page Directory will be at %lX', lf, 0
szIgnored DB 'Ignored commandline <%s>', lf, 0
;cant_disable_message db 'Can',27h,'t disable A20 - ignored',lf,'$'
dHimem db 'HimemSX: $'
;-- method feedback text
szKBC db "KBC",'$'
szPS2 db "PS/2",'$'
szFast db "Fast",'$'
szBIOS db "BIOS",'$'
szPort92 db "Port 92",'$'
szA20 db " A20 method used",13,lf,'$'
szAlwaysOn db 'Always on','$'
MsgUnknownA20 db 'No Supported A20 method detected',13,lf,'$'
old_dos db 'XMS needs at least DOS version 3.00.$'
xms_twice db 'XMS is already installed.$'
a20_error db 'Unable to switch A20 address line.$'
vdisk_detected db 'VDISK has been detected.$'
no_386 db 'At least a 80386 is required.$'
;xms_sizeerr db 'Unable to determine size of extended memory.$'
xms_toosmall db 'Extended memory is too small or not available.$'
error_msg db ' Driver won''t be installed.',7,13,10,'$'
methods label byte
db 3,"kbc" ;0 (A20_KBC)
db 3,"ps2" ;1 (A20_PS2)
db 4,"bios" ;2
db 8,"alwayson" ;3
db 4,"fast" ;4
db 6,"port92" ;5
db 0
if ?TESTMEM
?TMSTR equ <" /TESTMEM:ON|OFF">
else
?TMSTR equ <" ">
endif
if ?LOG
?LGSTR equ <" /LOG">
else
?LGSTR equ <" ">
endif
szHello label byte
db "Extended memory host for DOS (coordinates the usage of XMS and HMA).", lf
db "HimemSX is a device driver to be loaded in CONFIG.SYS.", lf
db "Place DEVICE=HIMEMSX.EXE [options] before any driver using XMS!", lf, lf
db "Options: /MAX=### /METHOD:xxx /HMAMIN=n /NUMHANDLES=m /V /X2MAX32 /SUPERMAX=###", lf
if ?TESTMEM or ?LOG
db ?TMSTR,?LGSTR, lf
endif
db lf
db " /MAX=### limit memory controlled by XMM to ###K.", lf
db " The HMA is not affected by this value, it's always included.", lf
db " /METHOD:xxx Specifies the method to be used for A20 handling.", lf
db " Possible values for xxx:", lf
db " ALWAYSON Assume that A20 line is permanently ON", lf
db " BIOS Use BIOS to toggle the A20 line", lf
db " FAST Use port 92h, bypass INT 15h test", lf
db " PS2 Use port 92h, bypass PS/2 test", lf
db " KBC Use the keyboard controller", lf
db " PORT92 Use port 92h always", lf
db " /HMAMIN=n Specifies minimum number of Kbs of HMA that a program", lf
db " must request to gain access to the HMA (default: 0Kb).", lf
db " /NUMHANDLES=m Set number of XMS handles (default: 48, min: 8, max: ",@CatStr(!",%MAXHANDLES,!"),").", lf
if ?TESTMEM
db " /TESTMEM:ON|OFF Performs or skips an extended memory test (def: OFF).", lf
endif
db " /SUPERMAX=### limit super-extended memory controlled by XMM to ###K.", lf
db " /V Gives extra information.", lf
db " /X2MAX32 Limit XMS 2.0 free/avail. memory report to 32M-1K.", lf
if ?LOG
db " /LOG Logs the driver activity to the screen.", lf
endif
db 0
_DATA ends
;******************************************************************************
; resident code and data
;******************************************************************************
_RTEXT segment
assume cs:DGROUP, ds:DGROUP
;******************************************************************************
; device driver header
dd -1 ; +0 last driver in list
dw 8000h ; +4 driver flags
dw offset strategy ; +6 pointer to strategy routine
dw offset init_interrupt ; +8 pointer to interrupt handler
db 'XMSXXXX0' ; device driver name
;******************************************************************************
; global data
;--- put some variables before gdt_start (so it is QWORD aligned)
a20_locks dw 0 ; internal A20 lock count
_x2max32 dw MAXFREEKB ; maximum XMS 2.0 free/available 32M
_hma_min dw 0 ; minimal space in HMA
gdt_start label near
gdt32 dw gdt_size-1,gdt_start,0
hma_used db 0 ; set if HMA is used
dummyretf:
retf
data32dsc desc <-1,0,0,92h,0cfh,0> ; 08 32-bit read/write data, 4G
data16dsc desc <-1,0,0,92h, 0h,0> ; 10 16-bit read/write data, 64k
if ?CATCHEXC
code16dsc desc <-1,0,0,9Ah, 0h,0> ; 18 16-bit read/exec code, 64k
code16sel equ 18h
videodsc desc <-1,8000h,0Bh,92h,0h,0>; 20 selector for vga segment B800h
videosel equ 20h
endif
gdt_size equ $ - offset gdt_start
data32sel equ 08h
data16sel equ 10h
xms_highest_addr dd 10FFFFh
xms_handle_table XMS_HANDLETABLE <0fdh, size XMS_HANDLE, 0, 0>
if ?CATCHEXC
gate struct
ofs dw ?
sel dw ?
attrib dw ?
ofs32 dw ?
gate ends
stdidt dw 3FFh,0,0
idt32 dw 19*sizeof gate-1,idt_start,0
idt_start label gate
gate <exc00+00,code16sel,08E00h,0>
gate <exc00+04,code16sel,08E00h,0>
gate <exc00+08,code16sel,08E00h,0>
gate <exc00+12,code16sel,08E00h,0>
gate <exc00+16,code16sel,08E00h,0>
gate <exc00+20,code16sel,08E00h,0>
gate <exc00+24,code16sel,08E00h,0>
gate <exc00+28,code16sel,08E00h,0>
gate <exc00+32,code16sel,08E00h,0>
gate <exc00+36,code16sel,08E00h,0>
gate <exc00+40,code16sel,08E00h,0>
gate <exc00+44,code16sel,08E00h,0>
gate <exc00+48,code16sel,08E00h,0>
gate <exc00+52,code16sel,08E00h,0>
gate <exc00+56,code16sel,08E00h,0>
gate <exc00+60,code16sel,08E00h,0>
gate <exc00+64,code16sel,08E00h,0>
gate <exc00+68,code16sel,08E00h,0>
gate <exc00+72,code16sel,08E00h,0>
EXCNO = 0
exc00 label near
rept 19
push EXCNO
jmp excxx
EXCNO = EXCNO+1
endm
excxx:
pop ax
shld cx,ax,12
and al,0Fh
add al,'0'
and cl,0Fh
add cl,'0'
cmp al,'9'
jbe @F
add al,7
@@:
mov ah,17h
mov ch,17h
shl eax,16
mov ax,cx
push videosel
pop ds
mov dword ptr ds:[0],17581745h
mov dword ptr ds:[4],173D1743h
mov dword ptr ds:[8],eax
jmp $
endif
align 4
;******************************************************************************
;--- A20 get status
; Out: ZF=0 - A20 enabled
; ZF=1 - A20 disabled
test_a20 proc
if 0
push ax
push ds
push es
xor ax,ax
mov ds,ax
dec ax
mov es,ax ; es->FFFF seg
assume es:DGROUP; es is NOT DGROUP, but this makes MASM happy
pushf ; save original flags (IF is important)
cli ; ensure interrupts are off while testing
mov ax,es:[10h] ; read word at FFFF:10h, the 1M limit
not ax ; ~1M word
push @word ds:[0] ; save word we're changing (INT 0 offset)
mov ds:[0],ax ; save ~1M word to 0:0 (and FFFF:10h if A20 disabled)
; mov ax,ds:[0] ; read back, may be unnecessary (forced memory access?)
cmp ax,es:[10h] ; compare 0:0 ~1M word to 1M word, only equal if A20 is disabled
pop @word ds:[0] ; restore INT 0 offset
lahf
popf
sahf
pop es
pop ds
pop ax
else
;--- this might be better: no need to disable interrupts and no memory
;--- is modified. 4 dwords are compared (0000:0010 and FFFF:0020)
push ds
push es
push cx
push si
push di
mov cx,-1
mov es,cx
mov si,10h
inc cx
mov ds,cx
mov di,20h
mov cl,4
repz cmpsd
pop di
pop si
pop cx
pop es
pop ds
endif
ret
test_a20 endp
;******************************************************************************
; enables the A20 address line
; currently dummy/always on, code replaced as A20 tests indicate
; all registers AND flags preserved!
enable_a20 proc
push ax
mov ah,2
jmp disable_enable_a20
enable_a20 endp
disable_a20 proc
push ax
mov ah,0
disable_a20 endp ;fall through
disable_enable_a20 proc ;patch area
;--- the default is the ALWAYSON "method", which is just a dummy
pop ax
ret
; since this is replaceable, we need to bulk up the space allocated for it
; for larger replacement routines
DB 42-2 DUP (?)
size_disable_enable_a20 equ $ - disable_enable_a20
disable_enable_a20 endp
;******************************************************************************
; Interrupt handlers
;******************************************************************************
;******************************************************************************
; new INT15h handler
;
; this externally preserves A20 state on function 87h
;
int15_handler proc
cmp ah,87h
je do_move
cmp ah,88h ; is it a ext. mem size req.?
je ext_mem_size
cmp ax,0E820h ; memory map?
je memmap
db 0EAh
old_int15 dd 0 ; old INT 15h vector
ext_mem_size:
xor ax,ax ; no memory available
exit_set_reset_carry:
push bp
mov bp,sp
rcr [bp+2].IRETS.bFlags,1
rol [bp+2].IRETS.bFlags,1
pop bp
exit_iret:
iret
do_move:
pushf
call test_a20
jz isdisabled
call cs:[old_int15]
call enable_a20 ; preserves flags
jmp exit_set_reset_carry
isdisabled:
call cs:[old_int15]
call disable_a20 ; preserves flags
jmp exit_set_reset_carry
memmap:
pushf
call cs:[old_int15]
jc exit_set_reset_carry
cmp eax,SMAP
jnz exit_iret
cmp es:[di].E820MAP.basehigh,0
jz exit_set_reset_carry
cmp es:[di].E820MAP.type_,1 ;"available" memory?
clc
jnz exit_set_reset_carry
mov byte ptr es:[di].E820MAP.type_,2 ;change to "reserved"
jmp exit_set_reset_carry
int15_handler endp
;******************************************************************************
; new INT2Fh handler. Catches Func. 4300h+4310h
int2f_handler proc
pushf
cmp ah,43h
je @@maybe_my2f
@@jmp_old2f:
popf
db 0EAh
old_int2f dd 0 ; old INT 2fh vector
@@maybe_my2f:
cmp al,00h ; is it "Installation Check"?
je @@get_driver_installed
cmp al,10h ; is it "Get Driver Address"?
je @@get_xms_address
cmp al,09h ; is it "get handle table"?
je @@get_xms_handle_table
cmp al,08h ; is it "get A20 handler number"?
jne @@jmp_old2f
mov al,ah ;al==43h if function supported
machine_type label byte
mov bx,0002 ;bh=switch time; 0=medium, 1=fast, 2=slow
popf ;bl=machine type; 01=std AT (KBC), 02=PS/2 (port 92)
iret
@@get_driver_installed:
mov al,80h ; yes, we are installed ;)
popf
iret
@@get_xms_address:
mov bx,offset xms_dispatcher
@@shared2f:
push cs
pop es
popf
iret
@@get_xms_handle_table:
mov al,ah ;al==43h if function supported
mov bx,offset xms_handle_table
jmp @@shared2f
int2f_handler endp
;******************************************************************************
; XMS functions
;******************************************************************************
; returns XMS version number
; In: AH=0
; Out: AX=XMS version number
; BX=internal revision number
; DX=1 if HMA exists, 0 if not
xms_get_version proc
mov ax,INTERFACE_VER
mov bx,DRIVER_VER
mov dx,1 ; HMA is always available
ret
xms_get_version endp
;******************************************************************************
; requests HMA
; In: AH=1
; DX=space needed in HMA (0ffffh if application tries to request HMA)
; Out: AX=1 if successful, BL=0 (MS Himem compatible)
; AX=0 if not successful
; BL=80h -> function not implemented (implemented here ;) )
; BL=81h -> VDISK is detected
; BL=90h -> HMA does not exist
; BL=91h -> HMA already in use
; BL=92h -> DX less than HMA_MIN
xms_request_hma proc
xor ax,ax
cmp [hma_used],al ; is HMA already used?
mov bl,XMS_HMA_IN_USE
jnz @@exit
cmp dx,[_hma_min] ; is request big enough?
mov bl,XMS_HMAREQ_TOO_SMALL
jb @@exit
inc ax
mov [hma_used],al ; assign HMA to caller
mov bl,0
@@exit:
ret
xms_request_hma endp
;******************************************************************************
; releases HMA
; In: AH=2
; Out: AX=1 if successful, BL=0 (MS Himem compatible)
; AX=0 if not successful
; BL=80h -> function not implemented
; BL=81h -> VDISK is detected
; BL=90h -> HMA doesn't exist
; BL=93h -> HMA wasn't allocated
xms_release_hma proc
xor ax,ax
cmp [hma_used],al ; is HMA used?
mov bl,XMS_HMA_NOT_USED
jz @@exit
mov [hma_used],al ; now release it
inc ax
mov bl,0
@@exit:
ret
xms_release_hma endp
;******************************************************************************
; global A20 address line enable
; In: AH=3
; Out: AX=1 if successful
; AX=0 if not successful
; BL=80h -> function is not implemented
; BL=81h -> VDISK is detected
; BL=82h -> A20 failure
xms_global_enable_a20 proc
call enable_a20 ; enable A20
call test_a20 ; is it really enabled?
jz error_A20_failure
xms_global_enable_a20 endp ; fall throu
xms_success:
mov ax,1
mov bl,0
ret
;******************************************************************************
; global A20 address line disable
; In: AH=4
; Out: AX=1 if successful (A20 is disabled)
; AX=0 if not successful
; BL=80h -> function is not implemented
; BL=81h -> VDISK is detected
; BL=82h -> A20 failure
; BL=94h -> A20 still enabled
xms_global_disable_a20 proc
IF ALLOWDISABLEA20
if 1
cmp [a20_locks],0
jnz error_A20_still_enabled
endif
call disable_a20 ; disable A20
call test_a20 ; is it really disabled?
jz xms_success
endif
error_A20_still_enabled::
xor ax,ax
mov bl,XMS_A20_STILL_ENABLED
ret
xms_global_disable_a20 endp
error_A20_failure:
xor ax,ax
mov bl,XMS_A20_FAILURE
ret
;******************************************************************************
; enables A20 locally
; In: AH=5
; Out: AX=1 if A20 is enabled, 0 otherwise
; BL=80h -> function not implemented
; BL=81h -> VDISK is detected
; BL=82h -> A20 failure
xms_local_enable_a20 proc
cmp [a20_locks],1
inc [a20_locks] ; increase lock counter
jc xms_global_enable_a20
jmp xms_success
xms_local_enable_a20 endp
;******************************************************************************
; disables A20 locally
; In: AH=6
; Out: AX=1 if A20 is disabled, 0 otherwise
; BL=80h -> function not implemented
; BL=81h -> VDISK is detected
; BL=82h -> A20 failure
; BL=94h -> A20 still enabled
xms_local_disable_a20 proc
cmp [a20_locks],0
jz error_A20_failure
dec [a20_locks] ; decrease lock counter
jnz error_A20_still_enabled
jmp xms_global_disable_a20
xms_local_disable_a20 endp
;******************************************************************************
; returns the state of A20
; In: AH=7
; Out: AX=1 if A20 is physically enabled, AX=0 if not
; BL=00h -> function was successful
; BL=80h -> function is not implemented
; BL=81h -> VDISK is detected
xms_query_a20 proc
xor ax,ax ; suppose A20 is disabled
call test_a20
setnz al
mov bl,0
ret
xms_query_a20 endp
;******************************************************************************
; alloc a XMS memory handle
; In: DS=CS
; Out: CY=1 - no free handle
; CY=0 - free handle found
; BX - offset of free handle
xms_alloc_handle proc
mov cx,[xms_handle_table.xht_numhandles] ; check all handles
mov bx, @word [xms_handle_table.xht_pArray]
@@nexthandle:
cmp [bx].XMS_HANDLE.xh_flags,XMSF_INPOOL
jz @@found_handle ; found a blank handle
add bx,sizeof XMS_HANDLE ; skip to next handle
loop @@nexthandle
stc ; no free block found, error
@@found_handle:
ret
xms_alloc_handle endp
;******************************************************************************
; xms_check_handle
; In: DS=CS
; SI - handle to check
;
; Out: CY=1 - no valid handle
; BL=0a2h - XMS_INVALID_HANDLE
; AX=0 - usual error return
;
; CY=0 - no error
;
; registers destroyed - AX
;
;-- called by
;-- xms_free_emb
;-- xms_move_emb
;-- xms_lock_emb
;-- xms_unlock_emb
;-- xms_ext_get_handle_info
;-- xms_ext_realloc_emb
xms_check_handle_ex:
mov si,dx
xms_check_handle proc
push dx
mov ax,si
sub ax, @word [xms_handle_table.xht_pArray]
jb @@no_valid_handle
xor dx,dx
push bx
mov bx,sizeof XMS_HANDLE
div bx
pop bx
or dx,dx
jnz @@no_valid_handle
cmp ax,[xms_handle_table.xht_numhandles] ; less then last handle ??
jae @@no_valid_handle
cmp [si].XMS_HANDLE.xh_flags,XMSF_USED ; is it in use ??
jne @@no_valid_handle
pop dx
xor ax,ax
ret
@@no_valid_handle:
pop dx
pop ax ;skip return address
xor ax,ax
mov bl,XMS_INVALID_HANDLE
stc
ret
xms_check_handle endp
;******************************************************************************
; query free super-extended memory
; In: AH=C8h
; Out: EAX=size of largest free super-extended block in kbytes
; EDX=total amount of free super-extended block in kbytes
; BL=0 if ok
; BL=080h -> function not implemented
; BL=081h -> VDISK is detected
; BL=0a0h -> all super-extended memory is allocated
xms_sext_query_free_mem proc
xor eax,eax ; contains largest free block
xor edx,edx ; contains total free block
push bx
pushf
cli
mov cx,[xms_handle_table.xht_numhandles]
mov bx, @word [xms_handle_table.xht_pArray]
nextitem:
test [bx].XMS_HANDLE.xh_flags,XMSF_FREE ; check if flagged free or in use
je @F
;--- filter blocks below 4 GB
;--- 00000000-003fffffh
test word ptr [bx].XMS_HANDLE.xh_baseK+2, 0ffc0h
jz @F
mov esi, [bx].XMS_HANDLE.xh_sizeK
add edx, esi
cmp esi, eax ; check if larger than largest
jbe @F
mov eax,esi ; larger, update
@@:
add bx,sizeof XMS_HANDLE
loop nextitem
popf ; restore IF
pop bx
mov bl,0
and edx,edx
jnz @@freeblockexists
mov bl,XMS_ALL_MEM_ALLOCATED
@@freeblockexists:
ret ; success
xms_sext_query_free_mem endp
;******************************************************************************
; query free extended memory
; In: AH=88h
; Out: EAX=size of largest free XMS block in kbytes
; ECX=highest ending address of any memory block
; EDX=total amount of free XMS in kbytes
; BL=0 if ok
; BL=080h -> function not implemented
; BL=081h -> VDISK is detected
; BL=0a0h -> all XMS is allocated
xms_ext_query_free_mem proc
xor eax,eax ; contains largest free block
xor edx,edx ; contains total free XMS
push bx
pushf
cli
mov cx,[xms_handle_table.xht_numhandles]
mov bx, @word [xms_handle_table.xht_pArray]
nextitem:
test [bx].XMS_HANDLE.xh_flags,XMSF_FREE ; check if flagged free or in use
je @F
;--- filter blocks beyond 4 GB
;--- 00000000-003fffffh
test word ptr [bx].XMS_HANDLE.xh_baseK+2, 0ffc0h
jnz @F
mov esi, [bx].XMS_HANDLE.xh_sizeK
add edx, esi
cmp esi, eax ; check if larger than largest
jbe @F
mov eax,esi ; larger, update
@@:
add bx,sizeof XMS_HANDLE
loop nextitem
popf ; restore IF
pop bx
mov bl,0
and edx,edx
jnz @@freeblockexists
mov bl,XMS_ALL_MEM_ALLOCATED
@@freeblockexists:
mov ecx,[xms_highest_addr] ; highest address to ecx return value
ret ; success