-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathINT67.PAS
314 lines (283 loc) · 9.25 KB
/
INT67.PAS
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
{
INT 67 - Expanded Memory Specification
Built with info from https://stanislavs.org/helppc/int_67.html
http://www.techhelpmanual.com/651-emm_functions.html
For extra info please check the bottom of this file
2022 LRT
}
unit
int67;
interface
const
{ basic status codes }
C_EMM_OK = 0;
C_EMM_INTERNAL_ERROR = $80;
C_EMM_HARDWARE_ERROR = $81;
C_EMM_BUSY = $82;
C_EMM_INVALID_HANDLE = $83;
C_EMM_UNDEFINED_FUNCTION = $84;
C_EMM_NO_MORE_HANDLES = $85;
C_EMM_ERROR_SAVE_RESTORE = $86;
C_EMM_ALLOC_LARGER_TOTAL = $87;
C_EMM_ALLOC_LARGER_PAGES = $88;
C_EMM_INVALID_PAGE_COUNT = $89;
C_EMM_INVALID_NUMBER_PAGES = $8A;
C_EMM_ILLEGAL_MAPPING = $8B;
C_EMM_SAVE_AREA_FULL = $8C;
C_EMM_SAVE_ONCE_PER_HANDLE = $8D;
C_EMM_CANT_RESTORE_WO_SAVE = $8E;
C_EMM_FUNCTION_ARG_UNDEF = $8F;
{ EMS 4.0 codes }
C_EMM_ATTR_TYPE_UNDEF = $90;
C_EMM_NONVOLATILITY_UNSUP = $91;
C_EMM_SRC_DST_OVERLAP = $92;
C_EMM_DEST_AREA_TOO_SMALL = $93;
C_EMM_CONV_MEM_OVERLAP_EMS = $94;
C_EMM_OFFSET_TOO_LARGE = $95;
C_EMM_BLOCKSIZE_TOO_LARGE = $96;
C_EMM_SRC_DST_HDLE_OVERLAP = $97;
C_EMM_SRC_DST_TYPE_INVALID = $98;
C_EMM_ALT_MAP_REG_UNSUPP = $9A;
C_EMM_ALL_REG_SETS_ALLOC = $9B;
C_EMM_ALL_REG_SETS_UNSUPP = $9C;
C_EMM_ALT_REG_USED_OR_INV = $9D;
C_EMM_DEDICATED_DMA_UNSUPP = $9E;
C_EMM_DMA_CHANNEL_UNSUPP = $9F;
C_EMM_NO_HANDLES_W_NAME = $A0;
C_EMM_NAME_ALREADY_EXISTS = $A1;
C_EMM_SRC_OFF_REG_LARGE = $A2;
C_EMM_PACKET_CONTENT_INV = $A3;
C_EMM_ACCESS_DENIED = $A4;
C_EMM_PAGE_SIZE = $4000;
C_EMM_FRAME0_OFFSET = $0000;
C_EMM_FRAME1_OFFSET = $4000;
C_EMM_FRAME2_OFFSET = $8000;
C_EMM_FRAME3_OFFSET = $C000;
{
Obtain the current status of the Expanded Memory Manager.
Use this only after establishing the presence of EMM support
}
function EMM_Status: byte;
{
Obtains the segment at which the EMS frame is mapped.
The EMS frame is a 64K area, often starting at d000:0. Depending
upon switches used when the driver is installed, the frame may
actually start at any segment address from 8000H to 9000H (seen
rarely) and c000H through e000H in increments of 400H.
When you read or write to EMS memory, you will use INT 67H 4000H
to map part of the EMS into this frame, then read or write to the
64K starting at the segment returned in BX.
}
function EMM_FrameSegment(var segAddr: word): byte;
{
Obtains the total amount of EMS memory that is supported and the
amount that is currently available.
}
function EMM_TotalMemory(var total, available: word): byte;
{
Allocates EMS memory.
The handle returned in DX is used in subsequent calls to map the
EMS into the page frame and other operations.
}
function EMM_OpenHandle(var handle: word; pages: word): byte;
{
Release memory allocated via INT 67H 4300H and makes the DX
handle invalid for future calls.
}
function EMM_CloseHandle(handle: word): byte;
{
This moves the data associated with a particular 16K page of EMS
memory into the physical frame (making that memory accessible).
For instance, assuming that the page frame starts at d000:0, then
calling this with AX=4401H will put the BXth page of your
allocation into d000:0400.
BX is the desired page of EMS memory. It can range from 0 to n-1,
where n is the size of the allocation (as used in INT 67H 4300H).
With EMS spec 4.0, you can set BX=ffffH to unmap a 16K portion of
the EMS frame. For instance, if AX=4401H and BX=ffffH, then the
data from EmsSeg:0400 through EmsSeg:07ff will be locked into
place and cannot be read or written. To remap a page, use the
same parameters, specifying a valid logical page number in BX.
Notes: You may remap only one 16K page at a time with this fn. You may
prefer INT 67H 50xxH to map multiple pages.
Page size: 4000h (16KB, 16384 bytes)
Frame addresses:
0: 0000h - 3FFFh
1: 4000h - 7FFFh
2: 8000h - BFFFh
3: C000h - FFFFh
}
function EMM_MapPageToFrame(physicalPage: byte; logicalPage: word; handle: word): byte;
{
Use this to ensure that the installed version supports any
special features you wish to access.
Notes: EMM 4.0 has been standard since 1987 and it is usually quite safe
to assume 4.0 is present. Furthermore, in most cases, you can
get by without using any of the features unique to 4.0.
}
function EMM_Version(var version: byte): byte;
{
EMS 4.0+
Resizes a handle, allowing to expand or shrink the number of pages
requested. When increasing the number of handles, the data on the
previous pages remains untouched.
}
function EMM_ResizeHandle(handle: word; pages: word): byte;
{
Some convenience functions to make this a little friendlier to use
}
function EMM_IsInstalled: boolean;
function EMM_FreePages: word;
implementation
function EMM_Status: byte;
var
_status: byte;
begin
asm
mov ax, 4000h
int 67h
mov _status, ah
end;
EMM_Status := _status;
end;
function EMM_FrameSegment(var segAddr: word): byte;
var
_status: byte;
_segAddr: word;
begin
asm
mov ax, 4100h
int 67h
mov _status, ah
mov _segAddr, bx
end;
EMM_FrameSegment := _status;
segAddr := _segAddr;
end;
function EMM_TotalMemory(var total, available: word): byte;
var
_status: byte;
_total: word;
_available: word;
begin
asm
mov ax, 4200h
int 67h
mov _status, ah
mov _total, dx
mov _available, bx
end;
EMM_TotalMemory := _status;
total := _total;
available := _available;
end;
function EMM_OpenHandle(var handle: word; pages: word): byte;
var
_status: byte;
_handle: word;
begin
asm
mov ax, 4300h
mov bx, pages
int 67h
mov _status, ah
mov _handle, dx
end;
EMM_OpenHandle := _status;
handle := _handle;
end;
function EMM_CloseHandle(handle: word): byte;
var
_status: byte;
begin
asm
mov ax, 4500h
mov dx, handle
int 67h
mov _status, ah
end;
EMM_CloseHandle := _status;
end;
function EMM_MapPageToFrame(physicalPage: byte; logicalPage: word; handle: word): byte;
var
_status: byte;
begin
asm
mov ah, 44h
mov al, physicalPage
mov bx, logicalPage
mov dx, handle
int 67h
mov _status, ah
end;
EMM_MapPageToFrame := _status;
end;
function EMM_Version(var version: byte): byte;
var
_status: byte;
_version: byte;
begin
asm
mov ax, 4600h
int 67h
mov _status, ah
mov _version, al
end;
EMM_Version := _status;
version := _version;
end;
function EMM_ResizeHandle(handle: word; pages: word): byte;
var
status: byte;
begin
asm
mov ax, $5100
mov bx, pages
mov dx, handle
int $67
mov status, ah
end;
EMM_ResizeHandle := status;
end;
function EMM_IsInstalled: boolean;
const
C_EXPECTED_DRIVER_NAME = 'EMMXXXX0';
type
TDeviceName = array[1..8] of char;
var
p: pointer;
begin
p := pointer(Ptr(0, $019c)^); { gets pointer to interrupt $67 handler 0000:$67*4 }
p := Ptr(Seg(p^), $0A); { offset $0A contains the driver device name }
EMM_isInstalled := TDeviceName(p^) = C_EXPECTED_DRIVER_NAME;
end;
function EMM_FreePages: word;
var
total, available: word;
begin
if EMM_TotalMemory(total, available) = C_EMM_OK then
EMM_freePages := available
else
EMM_freePages := 0;
end;
end.
{
This unit allows you to store data beyond conventional memory.
It requires expanded memory which, in really old times, consisted of
separate extension boards of memory that you physically connected in a
expansion slot in the same way you would add a video card. In newer
computers this is obtained thanks to EMM386 or similar drivers. EMM386
emulates expanded memory by using extended memory, which is a completely
different thing.
There is a segment, that you obtain via EMM_FrameSegment, which becomes your
point of access to that memory. This segment is divided in four frames, 16KB
each. What you do is, you open a handle and tell EMM386 how many pages you
need (a page is also 16KB). For instance, if you need 5MB (5120KB) you would
ask for 320 pages. Then you simply ask to load page 0 into any of those
frames, for instance, frame 0. You can load a completely different page in
another frame, for instance page 300 in frame 3 (as you see, there aren't more
than 4 frames, from 0 to 3). You read and write to this memory using pointers
as usual and changing the content in those frames. When you're done, you close
the frame. If you keep it open, later other programs might find out that there
isn't enough memory and you would have to reboot the computer.
}