source: vendor/emx/current/src/dos/swapper.asm

Last change on this file was 18, checked in by bird, 22 years ago

Initial revision

  • Property cvs2svn:cvs-rev set to 1.1
  • Property svn:eol-style set to native
  • Property svn:executable set to *
File size: 37.2 KB
Line 
1;
2; SWAPPER.ASM -- Swap memory pages in and out
3;
4; Copyright (c) 1991-1995 by Eberhard Mattes
5;
6; This file is part of emx.
7;
8; emx is free software; you can redistribute it and/or modify it
9; under the terms of the GNU General Public License as published by
10; the Free Software Foundation; either version 2, or (at your option)
11; any later version.
12;
13; emx is distributed in the hope that it will be useful,
14; but WITHOUT ANY WARRANTY; without even the implied warranty of
15; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16; GNU General Public License for more details.
17;
18; You should have received a copy of the GNU General Public License
19; along with emx; see the file COPYING. If not, write to
20; the Free Software Foundation, 59 Temple Place - Suite 330,
21; Boston, MA 02111-1307, USA.
22;
23; See emx.asm for a special exception.
24;
25
26 INCLUDE EMX.INC
27 INCLUDE OPRINT.INC
28 INCLUDE EXCEPT.INC
29 INCLUDE PMIO.INC
30 INCLUDE PAGING.INC
31 INCLUDE MEMORY.INC
32 INCLUDE PMINT.INC
33 INCLUDE SIGNAL.INC
34 INCLUDE PROCESS.INC
35 INCLUDE SEGMENTS.INC
36 INCLUDE TABLES.INC
37 INCLUDE DEBUG.INC
38
39 PUBLIC SWAP_HANDLE, SWAP_FLAG, SNATCH_COUNT
40 PUBLIC SWAP_FAULTS, SWAP_READS, SWAP_WRITES, SWAP_SIZE
41 PUBLIC PAGE_FAULT, SWAP_OUT, INIT_SWAP, ALLOC_SWAP
42 PUBLIC CLEANUP_SWAP, SET_TMP_DIR
43
44SER_FLAG = FALSE ; Don't use serial interface
45
46;
47; The page directory has two parts. The first 1024 entries contain
48; the page directory entries as required by the 386. The next 1024
49; entries are called the swap directory. Each entry is either zero
50; (no swap table) or contains the physical address of the swap table
51; associated with the page table.
52;
53; A swap table entry has the following format:
54;
55; 31 30 29 28 27 26 25 24 23 22 21 20 19 18 17 16 15 14 13 12
56; |---------------Page number in swap/exec file-------------|
57;
58; 11 10 09 08 07 06 05 04 03 02 01 00
59; 0 |A| |SRC| |----Process index----|
60;
61; Bits Description
62; 0-7 This identifies the owner of the page:
63; 00H not owned, not accessible
64; FFH (PIDX_SV) owned by supervisor
65; other process index of owner (cf. P_PIDX)
66; 8-9 This field tells where to get the page from:
67; SRC_NONE no source, just allocate (stack, for example)
68; SRC_ZERO zero fill (bss, for example)
69; SRC_EXEC executable file (code, for example)
70; SRC_SWAP swap file (modified data, for example)
71; 10 This bit is set if swap space is allocated to this page (SWAP_ALLOC)
72; 11 Currently not used
73; 12-31 Page number in executable/swap file, 0=not assigned
74;
75
76SV_DATA SEGMENT
77
78SWAP_ROVER DD ? ; Roving pointer for swapping out
79SNATCH_ROVER DD ? ; Roving pointer for getting swap pages
80
81SWAP_FAULTS DD 0 ; Number of page faults
82SWAP_READS DD 0 ; Number of swap file reads
83SWAP_WRITES DD 0 ; Number of swap file writes
84SNATCH_COUNT DD 0 ; Number of swap pages snatched
85SWAP_SIZE DD 0 ; Size of swap file
86
87;
88; Variables for SWAP_OUT
89;
90SO_SWAP_TABLE DD ? ; Address of swap table
91
92SWAP_HANDLE DW NO_FILE_HANDLE ; Handle of swap file
93SWAP_FLAG DB FALSE ; Swapping enabled (initially off)
94DISK_FULL DB FALSE ; Disk full while expanding swap file
95
96
97 IF DEBUG_SWAP
98$PF1 DB "Page fault, SRC=", 0
99$PF2 DB CR, LF, "Address=", 0
100$PF3 DB CR, LF, 0
101$SRC_NONE DB "NONE", 0
102$SRC_ZERO DB "ZERO", 0
103$SRC_EXEC DB "EXEC", 0
104$SRC_SWAP DB "SWAP", 0
105$SWAP_EXEC DB "File position=", 0
106 ENDIF
107
108$SWAP_OUT_OF_MEM DB "Out of memory or swap space", CR, LF, 0
109$SWAP_ERROR DB "Swap file I/O error", CR, LF, 0
110$SWAP_CREATE DB "Cannot create swap file", CR, LF, 0
111$SWAP_SPACE DB "Out of swap space", CR, LF, 0
112
113SWAP_FNAME DB 64+1+13 DUP (?)
114
115ZERO_BYTE DB 0
116
117SV_DATA ENDS
118
119
120
121SV_CODE SEGMENT
122
123 ASSUME CS:SV_CODE, DS:NOTHING
124
125 .386P
126
127 ASSUME DS:SV_DATA
128 ASSUME BP:PTR ISTACKFRAME
129PAGE_FAULT PROC NEAR
130 IF SER_FLAG
131 SERIAL "P"
132 ENDIF
133 MOV EAX, CR2 ; Get linear address of fault
134 STI ; Be venturous
135;
136; Protected-mode interrupt routines must not cause a page fault!
137; Protected-mode interrupt routines must not issue INT 21H (buffer)!
138; Protected-mode interrupt routines must not access the page tables!
139;
140 MOV FAULT_ADDR, EAX
141 TEST I_ERRCD, PAGE_PRESENT ; Caused by not-present page?
142 JNZ DUMP ; No -> dump
143 CMP EAX, LIN_START ; Address valid?
144 JB DUMP ; No -> dump
145 MOV BX, G_PAGEDIR_SEL
146 MOV ES, BX
147 MOV BX, G_PHYS_SEL
148 MOV FS, BX ; Setup physical addressing
149 SHR EAX, 22 ; Compute page directory index
150 MOV ESI, ES:[4*EAX+0] ; Get page directory entry
151 MOV EDI, ES:[4*EAX+4096] ; Get swap directory entry
152 TEST ESI, PAGE_PRESENT ; Page table present?
153 JZ DUMP ; No -> dump
154 OR EDI, EDI ; Is the swap table present?
155 JZ DUMP ; No -> dump
156 AND ESI, NOT 0FFFH ; Page table address
157 MOV EAX, FAULT_ADDR ; Get linear address of fault
158 SHR EAX, 12
159 AND EAX, 03FFH ; Page table index
160 LEA ESI, [ESI+4*EAX] ; Address of page table entry
161 LEA EDI, [EDI+4*EAX] ; Address of swap table entry
162 MOV EAX, FS:[EDI] ; Get swap table entry
163 MOV SWAP_PIDX, AL ; Save PIDX
164 CMP AL, PIDX_SV ; Supervisor page?
165 JE SHORT PF_PIDX_OK ; Yes -> ok
166 CMP AL, 01H ; PIDX >= 1?
167 JB DUMP
168 CMP AL, MAX_PROCESSES ; PIDX <= MAX_PROCESSES?
169 JA DUMP
170PF_PIDX_OK: MOV AX, BUF_SEG ; Current buffer segment
171 MOV BX, BUF2_SEG ; Segment of swapper buffer
172 CMP AX, BX ; Already in swapper?
173 JE DUMP ; Yes -> dump
174 MOV BUF_SEG, BX ; Switch to swapper buffer
175 MOV BUF_SEL, G_BUF2_SEL
176;
177; Don't jump to DUMP from here on, BUF_SEG and BUF_SEL changed!
178;
179 CALL GET_PROC ; Get process table entry
180 MOV FAULT_PROC, BX ; Save process pointer
181 OR BX, BX ; Supervisor?
182 JZ SHORT PF_SV_1 ; Yes -> skip
183 INC (PROCESS PTR [BX]).P_PAGE_FAULTS ; Process' counter
184PF_SV_1: INC SWAP_FAULTS ; Totals counter
185 IF DEBUG_SWAP
186 CMP DEBUG_FLAG, FALSE
187 JE SHORT PF_02
188 LEA EDX, $PF1
189 CALL OTEXT
190 MOV EAX, FS:[EDI] ; Get swap table entry
191 AND AX, SRC_MASK
192 LEA EDX, $SRC_ZERO
193 CMP AX, SRC_ZERO
194 JE SHORT PF_01
195 LEA EDX, $SRC_EXEC
196 CMP AX, SRC_EXEC
197 JE SHORT PF_01
198 LEA EDX, $SRC_SWAP
199 CMP AX, SRC_SWAP
200 JE SHORT PF_01
201 LEA EDX, $SRC_NONE
202PF_01: CALL OTEXT
203 LEA EDX, $PF2
204 CALL OTEXT
205 MOV EAX, FAULT_ADDR
206 CALL ODWORD
207 LEA EDX, $PF3
208 CALL OTEXT
209PF_02:
210 ENDIF
211 MOV EAX, FS:[ESI] ; Get page table entry
212 TEST AX, PAGE_ALLOC ; Memory allocated?
213 JZ SHORT PF_ALLOC ; No -> allocate memory
214 AND EAX, NOT 0FFFH ; Extract address
215 JMP SHORT PF_USE
216PF_ALLOC: CALL PM_ALLOC ; Allocate a page (swap out)
217 CMP EAX, NULL_PHYS ; Failure?
218 JE SWAP_OUT_OF_MEM ; Yes -> error
219PF_USE: MOV EDX, EAX ; Save physical address
220 MOV EAX, FS:[ESI] ; Page table entry
221 AND EAX, PAGE_CLEAR ; Clear address, P, D, A
222 OR EAX, EDX ; Insert phyiscal address
223 OR AX, PAGE_PRESENT OR PAGE_ALLOC ; Page present
224 MOV FS:[ESI], EAX ; Store page table entry
225 CALL CLEAR_TLB ; Clear TLB
226 AND EAX, NOT 0FFFH ; Extract physical address
227 MOV EDX, FS:[EDI] ; Get swap table entry
228 CALL LOAD_PAGE ; Initialize the page
229 AND WORD PTR FS:[ESI], NOT PAGE_DIRTY
230 CALL CLEAR_TLB
231PF_DONE:
232 IF STOP_SWAP AND DEBUG_SWAP
233 MOV AH, 01H
234 INT 21H
235 ENDIF
236 MOV AX, BUF1_SEG ; Switch back to main buffer
237 MOV BUF_SEG, AX
238 MOV BUF_SEL, G_BUF1_SEL
239 IF SER_FLAG
240 SERIAL "p"
241 ENDIF
242 JMP EXCEPT_RET
243
244;
245; Error while accessing swap file
246;
247SWAP_ERROR:: LEA EDX, $SWAP_ERROR
248 CALL OTEXT
249 MOV AX, 4CFFH
250 INT 21H
251 JMP $
252
253;
254; Cannot find a memory page for swapping in requested page
255;
256SWAP_OUT_OF_MEM:
257 LEA EDX, $SWAP_OUT_OF_MEM
258 CALL OTEXT
259 MOV AX, 4CFFH
260 INT 21H
261 JMP $
262
263DUMP: CLI
264 RET
265
266 ASSUME BP:NOTHING
267PAGE_FAULT ENDP
268
269
270
271;
272; Initialize a page in physical memory.
273;
274; This procedure fills the page with zeros, loads the page from the
275; exec file, loads the page from the swap file or does nothing
276; (stack pages).
277;
278; In: EAX Physical address
279; EDX Swap table entry
280;
281LOAD_PAGE PROC NEAR
282 PUSH ES ; Save registers
283 PUSH EAX
284 PUSH EBX
285 PUSH ECX
286 PUSH EDX
287 PUSH EDI
288 MOV EDI, EAX ; EDI := physical address
289 MOV AX, DX
290 AND AX, SRC_MASK ; Get type of source
291 CMP AX, SRC_NONE ; No source (stack)?
292 JE LP_NONE ; Yes -> done
293 CMP AX, SRC_ZERO ; Zero-filled (bss)?
294 JE LP_ZERO ; Yes -> fill
295 CMP AX, SRC_EXEC ; From exec file?
296 JE SHORT LP_EXEC ; Yes -> read from exec file
297;
298; Read from swap file
299;
300LP_SWAP: INC SWAP_READS ; Update statistics
301 AND EDX, NOT 0FFFH ; Extract address
302 MOV BX, SWAP_HANDLE ; Handle of swap file
303 MOV ECX, 4096 ; Read one page
304 JMP SHORT LP_READ ; (EDX is address in file)
305
306;
307; Fill page with zeros
308;
309LP_ZERO: MOV BX, G_PHYS_SEL
310 MOV ES, BX
311 MOV ECX, 1024
312 XOR EAX, EAX
313 CLD
314 REP STOS DWORD PTR ES:[EDI]
315 JMP LP_RET ; Done
316
317;
318; Read from exec file
319;
320LP_EXEC:
321 IF DEBUG_SWAP
322 CMP DEBUG_FLAG, FALSE
323 JE SHORT LP_EXEC_1
324 LEA EDX, $SWAP_EXEC
325 CALL OTEXT
326 MOV EAX, FS:[EDI]
327 AND EAX, NOT 0FFFH
328 CALL ODWORD
329 CALL OCRLF
330LP_EXEC_1:
331 ENDIF
332 MOV BX, FAULT_PROC
333 OR BX, BX ; Supervisor (cannot happen)?
334 JZ SWAP_ERROR ; Yes -> impossible (wrong msg)
335 ASSUME BX:PTR PROCESS
336 TEST [BX].P_FLAGS, PF_PRELOADING ; Preloading?
337 JNZ SHORT LP_ZERO ; Yes -> zero page
338 AND EDX, NOT 0FFFH ; Extract address
339 MOV ECX, 4096
340 MOV EAX, [BX].P_LAST_PAGE
341 OR EAX, EAX ; Incomplete last page?
342 JZ SHORT LP_EXEC_2 ; No -> skip
343 SHL EAX, 12
344 CMP EDX, EAX ; On last page?
345 JNE SHORT LP_EXEC_2 ; No -> skip
346 MOVZX ECX, [BX].P_LAST_BYTES ; Adjust number of bytes
347LP_EXEC_2: MOV EAX, [BX].P_SYM_PAGE
348 SHL EAX, 12
349 CMP EDX, EAX ; Symbol table page?
350 JB SHORT LP_EXEC_3 ; No -> skip
351 ADD EDX, [BX].P_RELOC_SIZE ; Adjust page address
352LP_EXEC_3: ADD EDX, [BX].P_EXEC_OFFSET ; Compute address in file
353 MOV BX, [BX].P_EXEC_HANDLE ; Get handle of exec file
354 ASSUME BX:NOTHING
355;
356; Load page from a file (BX=handle, EDX=address)
357;
358LP_READ: CALL SEEK ; Move file pointer
359 JC SWAP_ERROR ; Error -> abort
360 MOV EDX, EDI
361 MOV AX, G_PHYS_SEL ; Read page from file
362 CALL READ ; into physical memory
363 JC SWAP_ERROR ; Error -> abort
364 JNZ SWAP_ERROR ; Error -> abort
365 ADD EDI, ECX ; Compute end address
366 SUB ECX, 4096 ; Number of remaining bytes
367 JE SHORT LP_RET ; Complete page -> done
368 MOV AX, G_PHYS_SEL
369 MOV ES, AX ; Zero rest of page
370 NEG ECX ; Number of remaining bytes
371 XOR AL, AL
372 CLD
373 REP STOS BYTE PTR ES:[EDI]
374LP_NONE:
375LP_RET: POP EDI ; Restore registers
376 POP EDX
377 POP ECX
378 POP EBX
379 POP EAX
380 POP ES
381 RET
382LOAD_PAGE ENDP
383
384;
385; Get process table entry for process index
386;
387; In: SS:BP Exception stack frame with
388; SWAP_PIDX = process index
389;
390; Out: BX Pointer to process table entry or
391; 0000H supervisor page
392;
393GET_PROC PROC NEAR
394 MOVZX BX, SWAP_PIDX ; Get process index
395 CMP BL, PIDX_SV ; Supervisor?
396 JE SHORT GET_PROC_SV ; Yes -> return 0
397 DEC BX ; Now zero based
398 IMUL BX, SIZE PROCESS ; Compute offset
399 LEA BX, PROCESS_TABLE[BX] ; Compute address
400 RET
401GET_PROC_SV: XOR BX, BX ; Return 0 (supervisor)
402 RET
403GET_PROC ENDP
404
405;
406; Initialize the swap file bitmap. Attention: this causes page
407; faults!
408;
409INIT_SWAP PROC NEAR
410 MOV ECX, 4096 ; Bitmap size: 4096 bytes
411 LEA SI, G_SWAP_BMP_DESC ; Bitmap segment descriptor
412 CALL SV_SEGMENT ; Create segment
413 JC SHORT IS_RET ; Out of memory -> don't swap
414 MOV AX, G_SWAP_BMP_SEL
415 MOV ES, AX
416 XOR DI, DI
417 MOV ECX, 4096 / 4
418 XOR EAX, EAX
419 NOT EAX ; All pages free
420 CLD
421 REP STOS DWORD PTR ES:[DI]
422 MOV SWAP_FLAG, NOT FALSE
423 MOV EAX, LIN_START
424 MOV SWAP_ROVER, EAX
425 MOV SNATCH_ROVER, EAX
426IS_RET: RET
427INIT_SWAP ENDP
428
429
430;
431; Return (in EAX) the physical address of the swapped-out page
432; or NULL_PHYS if out of memory.
433;
434; (This code cannot handle swapping of page-tables (TLB!!!))
435;
436; Note: If SWAP_ROVER equals LIN_START and there are no pages present,
437; this code makes one superfluous, benign pass.
438;
439
440 ASSUME DS:SV_DATA
441SWAP_OUT PROC NEAR
442 CMP SWAP_FLAG, FALSE ; Swapping enabled?
443 JNE SHORT SO_1 ; Yes -> throw out a page
444 MOV EAX, NULL_PHYS ; Out of memory
445 RET
446
447SO_1: PUSH ES ; Save registers
448 PUSH FS
449 PUSH EBX
450 PUSH ECX
451 PUSH EDX
452 PUSH ESI
453 PUSH EDI
454 PUSH EBP
455 MOV AX, G_PAGEDIR_SEL
456 MOV FS, AX
457 MOV AX, G_PHYS_SEL
458 MOV ES, AX
459 MOV EDI, SWAP_ROVER
460 MOV BP, 0 ; Count number of rounds
461SO_LOOP1: MOV EAX, EDI ; Rover
462 SHR EAX, 22 ; Compute page directory index
463 MOV EBX, FS:[4*EAX] ; Get page directory entry
464 TEST EBX, PAGE_PRESENT ; Page table present?
465 JZ SHORT SO_NTBL0 ; No -> skip to next table
466 MOV EAX, FS:[4*EAX+4096] ; Address of swap table
467 OR EAX, EAX ; Does it exist?
468 JZ SHORT SO_NTBL0 ; No -> skip to next table
469 MOV SO_SWAP_TABLE, EAX ; Save address
470 AND EBX, NOT 0FFFH ; Address of page table
471 MOV EAX, EDI ; Compute page table index
472 SHR EAX, 12
473 AND EAX, 03FFH ; EAX := page table index
474 LEA ESI, [EBX+4*EAX] ; Address of page table entry
475 MOV ECX, 1024
476 SUB ECX, EAX ; Number of remaining entries
477 TALIGN 4
478SO_LOOP2: MOV EAX, ES:[ESI] ; Get page table entry
479 TEST AX, PAGE_ALLOC ; Memory allocated?
480 JZ SHORT SO_NEXT ; No -> skip
481;
482; We use only pages that are swappable and were not accessed since
483; the last round.
484;
485 TEST AX, PAGE_ACCESSED OR PAGE_LOCKED ; Both bits zero?
486 JZ SHORT SO_USE ; Yes -> use this page
487 TEST AX, PAGE_LOCKED ; Page locked?
488 JNZ SHORT SO_NEXT ; Yes -> skip
489 AND AL, NOT PAGE_ACCESSED ; Clear accessed bit
490 MOV ES:[ESI], AL ; Update page table entry
491 TALIGN 4
492SO_NEXT: ADD ESI, 4 ; Next entry
493 ADD EDI, 4096
494 LOOP SO_LOOP2 ; All page table entries
495 JMP SHORT SO_NTBL1 ; Next page table
496;
497; Skip to next page table
498;
499SO_NTBL0: AND EDI, NOT ((1 SHL 22) - 1) ; First page table entry
500 ADD EDI, 1 SHL 22 ; Next page table
501SO_NTBL1: OR EDI, EDI ; End of virtual memory?
502 JNZ SHORT SO_NTBL2 ; No -> continue
503 MOV EDI, LIN_START ; Restart from beginning
504 CMP BP, 2 ; Up to 2 rounds allowed
505 JAE SHORT SO_LOOSE ; More -> failure
506 INC BP ; Increment counter
507SO_NTBL2: JMP SO_LOOP1
508
509SO_LOOSE: MOV EAX, NULL_PHYS ; No pages found, sorry
510 JMP SO_RET
511
512;
513; Recycle this page
514;
515; If the page is dirty and the SWAP_ALLOC bit is not set, allocate a
516; swap page. If the page is dirty, write the page to the swap page.
517; Recycle the memory page by returning the address of the page.
518;
519 TALIGN 2
520SO_USE: MOV SWAP_ROVER, EDI
521 SUB EBX, ESI
522 NEG EBX ; Offset
523 ADD EBX, SO_SWAP_TABLE ; Address of swap table entry
524 TEST AL, PAGE_DIRTY ; Dirty page?
525 JZ SO_RECYCLE ; No -> just discard
526;
527; The page is present and dirty. Write it to the swap file.
528;
529 MOV EAX, ES:[EBX] ; Get swap table entry
530 TEST AX, SWAP_ALLOC ; Swap space allocated?
531 JZ SHORT SO_ALLOC ; No -> allocate swap space
532 MOV EDX, EAX ; Copy it (address!)
533 AND AX, NOT SRC_MASK ; Clear SRC field
534 OR AX, SRC_SWAP ; Reload page from swap file
535 AND EDX, NOT 0FFFH ; Extract page address
536 JMP SHORT SO_WRITE ; Write the page
537
538SO_ALLOC: CALL ALLOC_SWAP ; Allocate a page in swap file
539 JC OUT_OF_SWAP_SPACE ; Out of swap space
540 MOV EDX, EAX ; Address to EDX
541 MOV EAX, ES:[EBX] ; Get swap table entry
542 AND EAX, 0FFFH AND NOT SRC_MASK ; Clear address & SRC field
543 OR EAX, EDX ; Insert address into entry
544 OR AX, SRC_SWAP OR SWAP_ALLOC ; Reload page from swap file
545SO_WRITE: MOV ES:[EBX], EAX ; Update swap table entry
546 PUSH EBX
547 MOV BX, SWAP_HANDLE ; Handle of swap file
548 CALL SEEK ; Set file pointer to page
549 POP EBX ; (address in EDX)
550 JC SWAP_ERROR ; Error -> abort
551 INC SWAP_WRITES ; Update statistics
552 MOV EDX, ES:[ESI] ; Get physical address of
553 AND EDX, NOT 0FFFH ; the page
554 MOV AX, G_PHYS_SEL ; Write the page to the
555 MOV ECX, 4096 ; swap file
556 PUSH EBX
557 MOV BX, SWAP_HANDLE ; Handle of swap file
558 CALL WRITE
559 POP EBX
560 JC SWAP_ERROR ; Error -> abort
561 JNZ SWAP_ERROR ; disk full (cannot happen)
562;
563; Recycle the physical memory page.
564;
565SO_RECYCLE: MOV EAX, ES:[ESI] ; Get page table entry
566 MOV ECX, EAX ; Copy it
567 AND ECX, PAGE_CLEAR ; Clear address, P, D, A
568 AND CX, NOT PAGE_ALLOC ; Clear PAGE_ALLOC
569SO_DONE: MOV ES:[ESI], ECX ; Update the page table
570 AND EAX, NOT 0FFFH ; Extract address (ret value)
571 CALL CLEAR_TLB ; Clear the TLB
572SO_RET: POP EBP ; Restore registers
573 POP EDI
574 POP ESI
575 POP EDX
576 POP ECX
577 POP EBX
578 POP FS
579 POP ES
580 RET
581
582;
583; Out of swap space. Display message and abort.
584;
585OUT_OF_SWAP_SPACE:
586 LEA EDX, $SWAP_SPACE
587 CALL OTEXT
588 MOV AX, 4CFFH
589 INT 21H
590 JMP $
591SWAP_OUT ENDP
592
593;
594; Try to get a swap page by snatching the swap page of a present page
595; which has swap space allocated. This must not be done if PF_COMMIT
596; is set. The swap page stays marked as used!
597;
598; As SWAP_OUT calls SWAP_ALLOC only if swap space is not allocated,
599; and PAGE_FAULT calls PM_ALLOC only if the page is not pressent,
600; there is no danger of snatching the swap space of the page currently
601; operated on.
602;
603; Out: EAX External address of page (if NC), a multiple of 4096
604; CY Error (no page available)
605;
606
607 ASSUME DS:SV_DATA
608SNATCH_SWAP PROC NEAR
609 PUSH ES ; Save registers
610 PUSH FS
611 PUSH EBX
612 PUSH ECX
613 PUSH EDX
614 PUSH ESI
615 PUSH EDI
616 PUSH EBP
617 MOV AX, G_PAGEDIR_SEL
618 MOV FS, AX
619 MOV AX, G_PHYS_SEL
620 MOV ES, AX
621 MOV EDI, SNATCH_ROVER
622 MOV BP, 0
623SS_LOOP1: MOV EAX, EDI ; Rover
624 SHR EAX, 22 ; Compute page directory index
625 MOV EBX, FS:[4*EAX+0] ; Get page directory entry
626 TEST EBX, PAGE_PRESENT ; Page table present?
627 JZ SHORT SS_NTBL0 ; No -> skip to next table
628 MOV ESI, FS:[4*EAX+4096] ; Address of swap table
629 OR ESI, ESI ; Does it exist?
630 JZ SHORT SS_NTBL0 ; No -> skip to next table
631 AND EBX, NOT 0FFFH ; Address of page table
632 MOV EAX, EDI ; Compute page table index
633 SHR EAX, 12
634 AND EAX, 03FFH ; EAX := page table index
635 MOV ECX, 1024
636 SUB ECX, EAX ; Number of remaining entries
637 TALIGN 4
638SS_LOOP2: TEST WORD PTR ES:[EBX+4*EAX], PAGE_ALLOC ; Memory allocated?
639 JZ SHORT SS_NEXT ; No -> skip
640 TEST WORD PTR ES:[ESI+4*EAX], SWAP_ALLOC ; Swap space?
641 JNZ SHORT SS_USE ; Yes -> use this page
642SS_NEXT: INC EAX ; Next entry
643 ADD EDI, 4096
644 CMP EDI, SNATCH_ROVER ; All pages examined?
645 JE SHORT SS_FAIL ; Yes -> no page found
646 LOOP SS_LOOP2 ; All page table entries
647 JMP SHORT SS_NTBL1 ; Next page table
648;
649; Skip to next page table
650;
651SS_NTBL0: AND EDI, NOT ((1 SHL 22) - 1) ; First page table entry
652 ADD EDI, 1 SHL 22 ; Next page table
653SS_NTBL1: OR EDI, EDI ; End of virtual memory?
654 JNZ SHORT SS_NTBL2 ; No -> continue
655 MOV EDI, LIN_START ; Restart from beginning
656 INC BP ; In case SNATCH_ROVER points
657 CMP BP, 2 ; into a not-present page table
658 JAE SHORT SS_FAIL ; stop after 2 loops
659SS_NTBL2: JMP SS_LOOP1
660
661SS_FAIL: XOR EAX, EAX
662 STC ; No pages found
663 JMP SS_RET
664
665;
666; Use the swap space of this page. This is done by marking the
667; page as dirty, clearing the SWAP_ALLOC bit and returning the
668; address of the swap page.
669;
670 TALIGN 2
671SS_USE: MOV SNATCH_ROVER, EDI
672 INC SNATCH_COUNT ; Update statistics
673 OR BYTE PTR ES:[EBX+4*EAX], PAGE_DIRTY
674 LEA EDI, [ESI+4*EAX]
675 MOV EDX, ES:[EDI] ; Get swap table entry
676 MOV EAX, EDX
677 AND EAX, 0FFFH AND NOT SWAP_ALLOC
678 MOV ES:[EDI], EAX
679 MOV EAX, EDX
680 AND EAX, NOT 0FFFH ; Also clears CY flag
681 CALL CLEAR_TLB ; Clear the TLB (dirty bit!)
682SS_RET: POP EBP ; Restore registers
683 POP EDI
684 POP ESI
685 POP EDX
686 POP ECX
687 POP EBX
688 POP FS
689 POP ES
690 RET
691SNATCH_SWAP ENDP
692
693
694;
695; Open swap file
696;
697SWAP_OPEN PROC NEAR
698 CMP SWAP_HANDLE, NO_FILE_HANDLE
699 JNE SHORT SOP_9 ; Already open -> skip
700 PUSH EAX
701 PUSH ECX
702 PUSH EDX
703 PUSH ESI
704 PUSH EDI
705 PUSH ES
706 MOV AX, DS
707 LEA EDX, SWAP_FNAME
708 CALL CREATE_TMP ; Create temporary file
709 JC SHORT SOP_ERROR ; Error -> abort
710 MOV SWAP_HANDLE, AX ; Save file handle
711 POP ES
712 POP EDI
713 POP ESI
714 POP EDX
715 POP ECX
716 POP EAX
717SOP_9: RET
718
719SOP_ERROR: LEA EDX, $SWAP_CREATE
720 CALL OTEXT
721 MOV AX, 4CFFH
722 INT 21H
723 JMP $
724
725SWAP_OPEN ENDP
726
727;
728; Allocate a page in the swap file.
729;
730; 1. Create the swap file if it hasn't been opened yet.
731;
732; 2. Use a bitmap to locate a free page. If there is no page
733; available, return with CY set (error; this happens if the size
734; of the swap file exceeds 128 MB).
735;
736; 3. If the page is beyond the current end of the swap file
737; (taken from the SWAP_SIZE variable) expand the swap file.
738; If this succeeds, update the SWAP_SIZE variable. If expanding
739; the swap file fails, try to snatch a swap page. If this fails,
740; return with CY set (error). Expanding the swap file is not tried
741; if DISK_FULL is set (which is set if expanding the swap file
742; fails). If snatching a swap page fails, DISK_FULL is cleared
743; and ALLOC_SWAP tries again to expand the swap file.
744;
745; 4. Mark the page as used, clear CY (success) and return the page
746; address.
747;
748; Out: EAX External address of page (if NC), a multiple of 4096
749; CY Error
750;
751ALLOC_SWAP PROC NEAR
752 PUSH ES ; Save registers
753 PUSH EBX
754 PUSH ECX
755 PUSH EDX
756 PUSH EDI
757 CALL SWAP_OPEN ; Open swap file
758 MOV AX, G_SWAP_BMP_SEL
759 MOV ES, AX ; Access bitmap
760 XOR EDI, EDI ; Scan bitmap for a
761 MOV ECX, 4096 / 4 ; DWORD with at least
762 XOR EAX, EAX ; one bit set
763 CLD
764 REPE SCAS DWORD PTR ES:[EDI]
765 JE SHORT AS_FAIL ; All pages in use -> fail
766 SUB EDI, 4 ; Address of DWORD
767 BSF EAX, DWORD PTR ES:[EDI] ; Find bit in DWORD
768 JZ SHORT $ ; Cannot happen
769 SHL EDI, 3 ; 8 bits per bytes
770 ADD EDI, EAX ; Compute page number
771 SHL EDI, 12 ; Convert to page address
772 LEA EAX, [EDI+4096] ; End of page
773 CMP EAX, SWAP_SIZE ; Grow swap file?
774 JBE SHORT AS_OK ; No -> skip
775 CMP DISK_FULL, FALSE ; Disk full?
776 JNE SHORT AS_SNATCH ; Yes -> don't try to grow file
777 CALL GROW_SWAP ; Grow the swap file
778 JNC SHORT AS_OK ; Success -> done
779 CALL SNATCH_SWAP ; Try to snatch a swap page
780 JNC SHORT AS_RET ; Success -> done
781 JMP SHORT AS_FAIL ; Error
782
783AS_OK: MOV EAX, EDI ; Return page address in EAX
784 SHR EDI, 12 ; Compute bit number
785 BTR ES:[0], EDI ; Mark page as used
786 JNC SHORT $ ; Must not happen
787 CLC
788AS_RET: POP EDI ; Restore registers
789 POP EDX
790 POP ECX
791 POP EBX
792 POP ES
793 RET
794
795AS_SNATCH: CALL SNATCH_SWAP ; Try to snatch a swap page
796 JNC AS_RET ; Success -> use this page
797 MOV DISK_FULL, FALSE ; Try again to grow swap file
798 LEA EAX, [EDI+4096] ; New file size
799 CALL GROW_SWAP ; Disk full?
800 JNC SHORT AS_RET ; No -> success
801AS_FAIL: XOR EAX, EAX ; Set constant return value
802 STC ; Error
803 JMP SHORT AS_RET
804
805ALLOC_SWAP ENDP
806
807
808;
809; Grow the swap file
810;
811; In: EAX New size
812;
813; Out: CY Disk full
814;
815GROW_SWAP PROC NEAR
816 PUSH EAX ; Save registers
817 PUSH EBX
818 PUSH ECX
819 PUSH EDX
820 PUSH EAX ; Save size
821 MOV EDX, EAX ; New size of swap file
822 DEC EDX ; Address of (new) last byte
823 MOV BX, SWAP_HANDLE ; Handle of swap file
824 CALL SEEK ; Set file pointer to last byte
825 JC SWAP_ERROR ; Error -> abort
826 MOV AX, DS ; Write a byte just before the
827 LEA EDX, ZERO_BYTE ; (new) end of the file
828 MOV ECX, 1 ; (ECX=0 never fails!)
829 CALL WRITE ; Call INT 21H, function 40H
830 JC SWAP_ERROR ; Error -> abort
831 POP EAX ; Restore size
832 JNE SHORT GS_FAIL
833 MOV SWAP_SIZE, EAX ; Update variable (file size)
834 CLC ; Success
835 JMP SHORT GS_RET
836
837GS_FAIL: MOV DISK_FULL, NOT FALSE ; Set flag
838 STC ; Failure
839GS_RET: POP EDX
840 POP ECX
841 POP EBX
842 POP EAX
843 RET
844GROW_SWAP ENDP
845
846SV_CODE ENDS
847
848
849
850INIT_CODE SEGMENT
851
852 ASSUME CS:INIT_CODE, DS:NOTHING
853
854;
855; Set directory for temporary file
856;
857; In: DI=0 EMXTMP and TMP not set
858; ES:DI Pointer to value of EMXTMP (or TMP)
859;
860 ASSUME DS:SV_DATA
861SET_TMP_DIR PROC NEAR
862 OR DI, DI ; EMXTMP or TMP set?
863 JZ SHORT STD_DEFAULT ; No -> use \
864 LEA BX, SWAP_FNAME ; Copy value to SWAP_FNAME
865 MOV CX, 64 ; Copy up to 64 bytes
866STD_1: MOV AL, ES:[DI] ; Fetch byte from environment
867 MOV [BX], AL ; Store to SWAP_FNAME
868 INC DI
869 INC BX
870 OR AL, AL ; End reached?
871 JZ SHORT STD_RET ; Yes -> ok
872 LOOP STD_1 ; Repeat
873STD_DEFAULT: MOV SWAP_FNAME[0], "\" ; Use \ if EMXTMP/TMP not set
874 MOV SWAP_FNAME[1], 0 ; or if the value is too long
875STD_RET: RET
876SET_TMP_DIR ENDP
877
878
879;
880; Close and delete the swap file if it has been created.
881; If called from critical error handler, this should not be done.
882;
883 ASSUME DS:SV_DATA
884CLEANUP_SWAP PROC NEAR
885 MOV BX, NO_FILE_HANDLE ; Get handle of swap file
886 XCHG BX, SWAP_HANDLE ; and mark the file as closed
887 CMP BX, NO_FILE_HANDLE ; Swap file created?
888 JE SHORT CUW_RET ; No -> done
889 CMP CRIT_ERR_FLAG, FALSE ; Critical error?
890 JNE SHORT CUW_RET ; Yes -> skip
891 MOV AH, 3EH
892 INT 21H ; Close swap file
893 JC SHORT CUW_RET ; Error -> do not delete
894 LEA DX, SWAP_FNAME
895 MOV AH, 41H
896 INT 21H ; Delete swap file
897CUW_RET: RET
898CLEANUP_SWAP ENDP
899
900INIT_CODE ENDS
901
902 END
Note: See TracBrowser for help on using the repository browser.