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
|
page 58,132
;******************************************************************************
title EMMSUP - EMM support routines
;******************************************************************************
;
; (C) Copyright MICROSOFT Corp. 1986
;
; Title: CEMM.EXE - COMPAQ Expanded Memory Manager 386 Driver
; EMMLIB.LIB - Expanded Memory Manager Functions Library
;
; Module: EMMSUP - EMM support routines
;
; Version: 0.04
;
; Date: May 13, 1986
;
;******************************************************************************
;
; Change log:
;
; DATE REVISION DESCRIPTION
; -------- -------- -------------------------------------------------------
; 5/13/86 Original Initial _TEXT
; 6/14/86 Added _sotofar routine and removed stack define.
; And added protected mode check to Map_Page (SBP).
; 6/14/86 map_page now sets _current_map(SBP).
; 6/14/86 moved save_current_map and restore_map from C code (SBP)
; 6/14/86 brought SegOffTo24 and SetDescInfo in from LAST code
; segment as local routines(SBP).
; 6/21/86 0.02 cld in copyout (SBP).
; 6/21/86 0.02 MapHandlePage added.
; 6/23/86 0.02 make_addr, sotofar removed. source_addr and dest_addr
; added.
; 6/27/86 0.02 Fix for restore_map.
; 6/28/86 0.02 Name change from CEMM386 to CEMM (SBP).
; 7/06/86 0.04 Changed _emm_page,_emm_free, & _pft386 to ptrs (SBP).
; 7/06/86 0.04 Changed assumes from _DATA to DGROUP (SBP).
; 7/06/86 0.04 Changed internal save area structure (SBP).
; 7/06/86 0.04 moved SavePageMap and RestorePageMap to .ASM (SBP).
; 7/07/86 0.04 moved MapHandlePage,SavePageMap, and RestorePageMap to
; emmp.asm (SBP).
; 5/09/88 1.01 moved routines names_match and flush_tlb from win386
; 9/01/88 rename SegOffTo24/SetDescInfo to
; SegOffTo24Resident/SetDescInfoResdient and made public
;******************************************************************************
;
; Functional Description:
; Support routines for emm/386
; C callable
;
;
;******************************************************************************
.lfcond ; list false conditionals
.386p
;******************************************************************************
; P U B L I C S
;******************************************************************************
public _source_addr
public _dest_addr
public _copyout
public _copyin
public _wcopy
public _wcopyb
public _valid_handle
public SetDescInfoResident
public SegOffTo24Resident
;
;******************************************************************************
; D E F I N E S
;******************************************************************************
include vdmseg.inc
include vdmsel.inc
include desc.inc
include page.inc
; include instr386.inc
include emmdef.inc
FALSE equ 0
TRUE equ not FALSE
CR equ 0dh
LF equ 0ah
page
;******************************************************************************
; E X T E R N A L R E F E R E N C E S
;******************************************************************************
_DATA SEGMENT
;
; pointer to entry stack frame
; stored as offset, SS
extrn _regp:word
;
; current state of mapping registers and # of mapping registers emulated
;
;extrn _current_map:byte
;extrn _map_size:byte
;
; total # of EMM pages in system
;
extrn _total_pages:word
;
; table of offsets into in to the first page table
; for user logical emm page map
;
extrn _page_frame_base:dword
;
; ptr to table of emm page # for each handle's logical pages.
;
extrn _emm_page:word
;
; ptr to table of page table entries for the EMM pages
;
extrn _pft386:word ; note: actually a dword array
;
; handle data structure
;
extrn _handle_table:word
extrn _handle_table_size:word
;
; save area for handles
;
extrn _save_map:byte
_DATA ENDS
page
;******************************************************************************
; L O C A L D A T A
;******************************************************************************
_DATA SEGMENT
;
; kludge to prevent unresolved from C compiler
;
public __acrtused
__acrtused label dword
dd (0)
_DATA ENDS
page
;******************************************************************************
; C O D E
;******************************************************************************
_TEXT SEGMENT
assume cs:_TEXT, ds:DGROUP, ss:DGROUP
;***********************************************
;
; _source_addr - return far pointer for source address (= int 67 entry DS:SI).
;
; SYNOPSIS: src = source_addr()
; char far *src; /* ptr to area at DS:SI */
;
; DESCRIPTION: This function generates a far pointer equivalent to the client's
; DS:SI pointer. If this code was called in protected mode, the
; address is a (selector,offset) pair; otherwise, it is a segment
; offset pair. EMM1_GSEL is used if a selector is needed.
;
; 05/09/88 ISP No update needed for MEMM
;***********************************************
_source_addr proc near
;
push bp
;
mov bp,[_regp] ; get entry stack frame pointer
test [bp.PFlag],PFLAG_VIRTUAL ;Q: real/virtual mode ?
jnz sa_pm ; N: go get selector/offset
mov ax,word ptr [bp.rSI] ; Y: get offset
mov dx,word ptr [bp.rDS] ; get segment
jmp sa_exit ; return DX:AX = seg:offset
;
; protected mode - set up selector to client's DS
sa_pm:
push bx
push cx
push es ; save ES
;
; load ES with GDT alias
;
push GDTD_GSEL
pop es ; ES -> GDT
;
; compute physical address
;
mov ax,word ptr [bp.rDS] ; ax <-- base addr
mov dx,word ptr [bp.rSI] ; dx <-- offset
call SegOffTo24Resident ; converts to physical addr
;
; set up the appropriate table entry
;
mov bx,EMM1_GSEL ; bx <-- selector
mov cx,0FFFFh ; cx <-- gets limit (64k)
mov ah,D_DATA0 ; ah <-- gets access rights
;
; at this point:
; ah -- access rights
; al -- bits 16-23 of linear address
; dx -- low 16 bits of linear address
; cx -- limit = 64k
; bx -- selector
; es -- selector to GDT Alias
call SetDescInfoResident ; set up descriptor
;
; set up return pointer
;
xor ax,ax ; ax <-- offset (0)
mov dx,bx ; dx <-- selector
;
pop es ; restore ES
pop cx
pop bx
;
sa_exit:
pop bp
ret
;
_source_addr endp
;***********************************************
;
; _dest_addr - return far pointer for destination address (= int 67 entry ES:DI).
;
; SYNOPSIS: dest = dest_addr()
; char far *dest; /* ptr to area at ES:DI */
;
; DESCRIPTION: This function generates a far pointer equivalent to the client's
; ES:DI pointer. If this code was called in protected mode, the
; address is a (selector,offset) pair; otherwise, it is a segment
; offset pair. EMM2_GSEL is used if a selector is needed.
;
; 05/09/88 ISP No update needed for MEMM
;***********************************************
_dest_addr proc near
;
push bp
;
mov bp,[_regp] ; get entry stack frame pointer
test [bp.PFlag],PFLAG_VIRTUAL ;Q: real/virtual mode ?
jnz da_pm ; N: go get selector/offset
mov ax,word ptr [bp.rDI] ; Y: get offset
mov dx,word ptr [bp.rES] ; get segment
jmp da_exit ; return DX:AX = seg:offset
;
; protected mode - set up selector to client's DS
da_pm:
push bx
push cx
push es ; save ES
;
; load ES with GDT alias
;
push GDTD_GSEL
pop es ; ES -> GDT
;
; compute physical address
;
mov ax,word ptr [bp.rES] ; ax <-- base addr
mov dx,word ptr [bp.rDI] ; dx <-- offset
call SegOffTo24Resident ; converts to physical addr
;
; set up the appropriate table entry
;
mov bx,EMM2_GSEL ; bx <-- selector
mov cx,0FFFFh ; cx <-- gets limit (64k)
mov ah,D_DATA0 ; ah <-- gets access rights
;
; at this point:
; ah -- access rights
; al -- bits 16-23 of linear address
; dx -- low 16 bits of linear address
; cx -- limit = 64k
; bx -- selector
; es -- selector to GDT Alias
call SetDescInfoResident ; set up descriptor
;
; set up return pointer
;
xor ax,ax ; ax <-- offset (0)
mov dx,bx ; dx <-- selector
;
pop es ; restore ES
pop cx
pop bx
;
da_exit:
pop bp
ret
;
_dest_addr endp
page
;***********************************************
;
; _copyout
;
; This routine takes a far pointer, a near pointer
; and a byte count and copies from the near address
; to the far address.
;
; Parameters:
; destptr -- sel:off 286 pointer to target area
; srcptr --- offset of source data in current D Seg
; count ---- byte count for copy
;
; uses:
; cx, ax, es
;
; 05/09/88 ISP No update needed for MEMM
;***********************************************
destptr = 4
srcptr = 8
count = 10
_copyout proc near
push bp ; entry prolog
mov bp,sp
push di ; reg var
push si ; reg var
les di,[bp+destptr] ; es:di <-- destination address
mov si,[bp+srcptr] ; ds:si <-- source address
mov cx,[bp+count] ; cx <-- byte count
cld ; strings foward
rep movsb ; do it
pop si ; restore reg var
pop di ; restore reg var
pop bp
ret
_copyout endp
page
;***********************************************
;
; _copyin
;
; This routine takes a near pointer, a far pointer
; and a byte count and copies from the far address
; to the near address.
;
; Parameters:
; destptr -- offset of dest in current D Seg
; srcptr --- sel:off 286 pointer to source data area
; count ---- byte count for copy
;
; uses:
; cx, ax, es
;
; 05/09/88 ISP Written for MEMM.
;***********************************************
destptr = 4
srcptr = 6
count = 10
_copyin proc near
push bp ; entry prolog
mov bp,sp
push di ; reg var
push si ; reg var
push ds
push ds
pop es ; es to dgroup
mov di,[bp+destptr] ; es:di <-- destination address
lds si,[bp+srcptr] ; ds:si <-- source address
mov cx,[bp+count] ; cx <-- byte count
cld ; strings foward
rep movsb ; do it
pop ds
pop si ; restore reg var
pop di ; restore reg var
pop bp
ret
_copyin endp
page
;***********************************************
;
; _wcopy
;
; This routine takes a two near pointers
; and a word count and copies from the
; first address to the second address.
;
; Parameters:
; srcptr --- offset of source data in current D Seg
; destptr -- offset of destination address in DS
; count ---- word count for copy
;
; uses:
; si, di, cx, ax
; (si, di are restored)
;
; 05/09/88 ISP No update needed for MEMM
;***********************************************
srcptr = 4
destptr = 6
count = 8
_wcopy proc near
push bp ; entry prolog
mov bp,sp
push di ; reg var
push si ; reg var
cld ; clear dir flag (forward move)
mov ax,ds ;
mov es,ax ; mov es,ds
mov di,[bp+destptr] ; es:di <-- destination address
mov si,[bp+srcptr] ; ds:si <-- source address
mov cx,[bp+count] ; cx <-- word count
rep movsw ; do it
pop si ; restore reg var
pop di ; restore reg var
pop bp
ret
_wcopy endp
page
;***********************************************
;
; _wcopyb
;
; This routine takes a two near pointers
; and a word count and copies from the
; first address to the second address.
; The copy is done backwards to allow certain overlap of source and destination.
;
; Parameters:
; srcptr --- offset of source data in current D Seg
; destptr -- offset of destination address in DS
; count ---- word count for copy
;
; uses:
; si, di, cx, ax, es
; (si, di are restored)
;
; 05/20/88 ISP Shifted in from win386 and updated for 16 bit ptrs
;***********************************************
srcptr = 4
destptr = 6
count = 8
_wcopyb proc near
push bp ; entry prolog
mov bp,sp
push di ; reg var
push si ; reg var
mov ax,ds ;
mov es,ax ; mov es,ds
mov di, word ptr [bp+destptr] ; destination address
mov si, word ptr [bp+srcptr] ; source address
mov cx, word ptr [bp+count] ; word count
dec cx
shl cx, 1 ; offset of 'last' word to move
add si, cx
add di, cx
mov cx, word ptr [bp+count] ; recover word count
std ; set dir flag (backward move)
rep movsw ; do it
cld ; 'C' tends to expect this.
pop si ; restore reg var
pop di ; restore reg var
pop bp
ret
_wcopyb endp
page
;***********************************************
;
; _valid_handle - validate current handle
;
; SYNOPSIS: hp = _valid_handle()
; struct handle_ptr *hp; /* ptr to handle's structure */
; /* OR NULL_HANDLE if invalid handle */
; /* also sets AH = INVALID_HANDLE if it fails */
;
; DESCRIPTION: This routine validates the current handle in regp->rDX and
; returns either an error or a ptr to the handle's index and
; page count structure.
;
; 05/09/88 ISP No update needed for MEMM
;***********************************************
_valid_handle proc near
;
push bp
mov bp,[_regp] ; get entry args pointer
push bx
;
mov bx,word ptr [bp.rDX] ; BX = entry handle
cmp bx,[_handle_table_size] ;Q: handle in range ?
jae vh_fail ; N: return invalid handle error
shl bx,2 ; Y: BX = handle's table offset
add bx,offset DGROUP:_handle_table ; BX = offset to handle's data
cmp [bx.ht_index],NULL_PAGE ;Q: is this an active handle ?
je vh_fail ; N: return invalid handle error
mov ax,bx ; Y: return ptr to handle's data
;
vh_exit:
pop bx
pop bp
ret
vh_fail:
mov byte ptr [bp.rAX+1],INVALID_HANDLE ; set AH on stack
mov ax,NULL_HANDLE ; return NULL_HANDLE to caller
jmp short vh_exit
;
_valid_handle endp
;***********************************************
;
; flush_tlb:
;
; no params, no return value, uses eax
;
; flush the Translation Look-Aside Buffer
;
; 05/09/88 ISP Shifted in from WIN386
;***********************************************
_flush_tlb proc near
public _flush_tlb
mov eax, cr3
mov cr3, eax
ret
_flush_tlb endp
;***********************************************
;
; _Names_Match
;
; Returns a boolean value (0 = false, FFFF = True) if 2 handle names match
;
; uses:
; cx, ax
;
; 05/09/88 ISP Shifted in from WIN386 and modified for 16 bit ptrs
;***********************************************
name1 = 4
name2 = 6
public _Names_Match
_Names_Match proc near
push bp ; entry prolog
mov bp,sp
push di ; reg var
push si ; reg var
mov ax,ds ; initialise es segment to
mov es,ax ; DGROUP
xor ax, ax ; Assume it did NOT work
mov di, word ptr [bp+name1] ; First name
mov si, word ptr [bp+name2] ; Second name
cld
mov cx, 2 ; Compare 2 dwords
rep cmpsd ; do it
jne SHORT Names_Dont_Match
not ax ; They match!
Names_Dont_Match:
pop si ; restore reg var
pop di ; restore reg var
pop bp
ret
_Names_Match endp
page
;** SetDescInfoResident - set descriptor information
;
; The limit field of a specified descriptor is set.
; (limit = size - 1).
; The base address of the specified descriptor is set.
; The access field of the specified descriptor is set.
;
; ENTRY BX = selector
; ES:0 = descriptor table to use
; CX = limit
; AL, DX = 24 bit base address
; AH = access rights byte
; EXIT None
; USES Flags, other regs preserved
;
; WARNING This code only works on a 286. It can be called in
; either mode.
SetDescInfoResident proc near
push bx ; save selector
and bl,SEL_LOW_MASK
; fill in the limit field
mov es:[bx],cx
; fill in base address
mov es:[bx + 2],dx
mov es:[bx + 4],al
; fill in access rights byte
mov es:[bx + 5],ah
pop bx
ret
SetDescInfoResident endp
page
;** SegOffTo24Resident - convert seg:off to 24 bit physical address
;
; The specified real mode segment:offset is converted to
; a 24 bit physical address.
;
; ENTRY AX = segment
; DX = offset
; EXIT AL, DX = 24 bit physical address
; USES AH, Flags, other regs preserved.
;
; WARNING This code only works on a 286. It can be called in
; either mode.
SegOffTo24Resident proc near
push cx
; Convert AX:DX into 24 bit addr in AL, DX
mov ch,ah
shl ax,4
shr ch,4 ; CH = high byte
add dx,ax ; DX = low word
mov al,ch ; AL = high byte
adc al,0 ; propagate cy from low word
pop cx
ret
SegOffTo24Resident endp
_TEXT ENDS
END
|