source: vendor/emx/current/src/dos/paging.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: 35.5 KB
Line 
1;
2; PAGING.ASM -- Manage page tables
3;
4; Copyright (c) 1991-1999 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__PAGING = 1
27
28 INCLUDE EMX.INC
29 INCLUDE OPRINT.INC
30 INCLUDE MEMORY.INC
31 INCLUDE TABLES.INC
32 INCLUDE SEGMENTS.INC
33 INCLUDE VCPI.INC
34 INCLUDE PAGING.INC
35 INCLUDE SWAPPER.INC
36 INCLUDE MISC.INC
37
38 PUBLIC PAGE_DIR_PHYS, PAGE_DIR_SEG, PAGE_TAB0_SEG
39 PUBLIC LIN_START, PAGING
40 PUBLIC ALLOC_PAGES, INIT_PAGES, SET_PAGES, CLEAR_TLB
41 PUBLIC INIT_LIN_MAP, FREE_LIN, FREE_PAGES, GET_FREE_PAGE
42 PUBLIC INIT_PAGE_BMAP, FREE_AVAIL, CLEAR_DIRTY
43 PUBLIC INIT_PAGING, MAP_PAGES, RM_TO_PHYS, MAYBE_MAP_PAGE
44
45;
46; This constant limits physical memory (unless VCPI is used). The
47; value is specified in MB. Must be a multiple of 4.
48;
49MAX_PHYS_MEM = 1024 ; 1 GB
50
51SV_DATA SEGMENT
52
53PAGE_DIR_PHYS DD ? ; Physical address of page directory
54 ; Use only for putting into CR3!
55PAGE_DIR_SEG DW ? ; Real-mode segment of page directory
56 ; and swap directory
57PAGE_TAB0_SEG DW ? ; Real-mode segment of page table 0
58
59TEMP_PAGE_SEG DW ? ; Page for use as temporary page table
60TEMP_PAGE_PHYS DD ? ; during memory allocation
61;
62; Managing linear addresses. Linear addresses are divided into 4096 blocks
63; of size 1M each. There's a table containing 4096 bytes, one for each
64; block. This byte is either 0 (not allocated), 1..254 (allocated to
65; the process with that process index), or 255 (reserved or allocated
66; to supervisor).
67;
68; This could also be done by scanning page tables, but that seems to be
69; more complicated.
70;
71; There's a chicken and egg problem: We have to allocate some linear
72; addresses for creating this segment. Allocating linear addresses
73; requires this segment. Solution: Allocate the segment in real mode.
74; This is simple but wastes low memory. The segment contents are not
75; initialized in real mode to avoid duplication of code.
76;
77LIN_MAP_SEG DW ? ; Real-mode segment
78
79;
80; First usable linear address, used for initializing linear address map etc.
81;
82; Linear address below this address map identically to physical addresses
83; (G_PHYS_SEL)
84;
85LIN_START DD ?
86
87;
88; We use a bitmap for keeping track of freed pages (FREE_PAGES). We do
89; not use SWAP_OUT for allocating freed pages, as SWAP_OUT just swaps
90; out the next page with PAGE_ACCESSED cleared (even if it must be
91; reloaded from a file or is dirty). For efficiency (memory/disk space),
92; freed pages must be reused before trying to swap out pages. To avoid
93; scanning the bitmap each time we need a page of physical memory, we
94; use a variable for counting freed pages.
95;
96FREED_PAGES DD 0
97PAGE_BMAP_FLAG DB FALSE ; Page bitmap enabled?
98
99;
100; Paging enable flag.
101;
102PAGING DB FALSE ; Paging disabled
103
104$ALLOC_PAGES DB "Linear address space exhausted", CR, LF, 0
105
106 IF DEBUG_MAP
107$MMP1 DB "Map phys=", 0
108$MMP2 DB " lin=", 0
109 ENDIF
110SV_DATA ENDS
111
112
113
114SV_CODE SEGMENT
115
116 .386P
117
118 ASSUME CS:SV_CODE, DS:NOTHING
119
120
121;
122; Initialize linear address map. Creating segments (SV_SEGMENT) is possible
123; only after calling this routine.
124;
125; Reserved linear addresses: 0 ... LIN_START-1
126;
127; Available linear addresses: LIN_START ... 0FFFFFFFFH
128;
129; This code requires LIN_START to be a multiple of the linear address
130; block size (1M). Other code requires it to be a multiple of 4M.
131; Both INIT_PAGING and INIT_VCPI make LIN_START a multiple of 4M.
132;
133 ASSUME DS:SV_DATA
134INIT_LIN_MAP PROC NEAR
135 MOV AX, G_LIN_MAP_SEL
136 MOV ES, AX
137 CLD
138 MOV EBX, LIN_START
139 TEST EBX, (1 SHL 22)-1 ; Must be a multiple of 4M
140 JNZ SHORT $ ; Impossible!
141 SHR EBX, 20 ; Divide by 1M
142 MOV CX, BX
143 XOR DI, DI
144 MOV AL, PIDX_SV ; Address reserved
145 REP STOS BYTE PTR ES:[DI]
146 MOV AL, 00H ; Address available
147 MOV CX, 4096
148 SUB CX, BX
149 REP STOS BYTE PTR ES:[DI]
150 RET
151INIT_LIN_MAP ENDP
152
153
154;
155; Allocate a range of pages
156;
157; In: ECX Number of bytes
158; AL Process index
159;
160; Out: EAX Linear address
161; ECX Number of pages
162;
163
164 ASSUME DS:SV_DATA
165ALLOC_PAGES PROC NEAR
166 PUSH ES
167 PUSH DX
168 PUSH DI
169 ADD ECX, 0FFFH ; Round up (pages)
170 AND ECX, NOT 0FFFH
171 PUSH ECX ; Save size
172 ADD ECX, (1 SHL 20) - 1 ; Round up (1M)
173 SHR ECX, 20 ; Number of 1M blocks
174 MOV DX, G_LIN_MAP_SEL
175 MOV ES, DX
176 XOR DI, DI
177 XOR DX, DX ; 0 blocks found
178 MOV AH, AL ; Save process index in AH
179 XOR AL, AL ; Search for empty blocks
180AP_LOOP: CMP DI, 4096
181 JAE SHORT AP_FAIL ; Nothing found -> abort
182 SCAS BYTE PTR ES:[DI] ; Block available?
183 JE SHORT AP_AVAILABLE ; Yes -> increment counter
184 XOR DX, DX ; Reset counter
185 JMP SHORT AP_LOOP
186
187AP_AVAILABLE: INC DX ; Increment counter
188 CMP DX, CX ; Enough blocks found?
189 JB SHORT AP_LOOP ; No -> continue
190 SUB DI, CX ; Starting block number
191 MOV DX, DI ; Save it
192 CLD
193 MOV AL, AH ; Get process index
194 REP STOS BYTE PTR ES:[DI] ; Allocate linear addresses
195 MOVZX EAX, DX ; Get block number
196 SHL EAX, 20 ; Compute linear address
197 POP ECX
198 SHR ECX, 12 ; ECX := number of pages
199 POP DI
200 POP DX
201 POP ES
202 RET
203
204AP_FAIL: LEA EDX, $ALLOC_PAGES ; Linear address space
205 CALL OTEXT ; exhausted
206 MOV AX, 4CFFH ; Abort
207 INT 21H
208
209ALLOC_PAGES ENDP
210
211
212;
213; Free linear address space of a (dead) process
214;
215; In: AL Process index (most not be 0FFH!)
216;
217 ASSUME DS:SV_DATA
218FREE_LIN PROC NEAR
219 PUSH ES
220 PUSH CX
221 PUSH DI
222 MOV CX, G_LIN_MAP_SEL
223 MOV ES, CX
224 MOV CX, 4096 ; Examine 4096 entries
225 XOR DI, DI ; Start with entry 0
226FL_LOOP: SCAS BYTE PTR ES:[DI] ; Matching entry?
227 JNE SHORT FL_NEXT ; No -> skip
228 MOV BYTE PTR ES:[DI-1], 0 ; Make block available
229FL_NEXT: LOOP FL_LOOP
230 POP DI
231 POP CX
232 POP ES
233 RET
234FREE_LIN ENDP
235
236
237;
238; Adjust page tables of killed process
239;
240; In: AL Process index (must not be 00H!)
241;
242 ASSUME DS:SV_DATA
243FREE_PAGES PROC NEAR
244 PUSH ES
245 PUSH FS
246 PUSH GS
247 PUSHAD
248 MOV CX, G_PAGEDIR_SEL
249 MOV FS, CX ; FS: page directory
250 MOV CX, G_PHYS_SEL
251 MOV ES, CX ; ES: page tables
252 XOR EBX, EBX
253 MOV DL, AL ; Save process index
254FP_LOOP1: MOV ESI, FS:[EBX] ; Get page directory entry
255 TEST ESI, 1 ; Page table present?
256 JZ FP_NEXT_TABLE ; No -> skip to next table
257 MOV EDI, FS:[EBX+4096] ; Address of swap table
258 OR EDI, EDI ; Does it exist?
259 JZ FP_NEXT_TABLE ; No -> skip to next table
260 AND ESI, NOT 0FFFH ; Address of page table
261 MOV CX, 1024
262FP_LOOP2: CMP DL, ES:[EDI] ; Matching process index?
263 JNE SHORT FP_NEXT_PAGE
264 TEST WORD PTR ES:[EDI], SWAP_ALLOC ; Swap space allocated?
265 JZ SHORT FP_FREE1 ; No -> skip
266 MOV AX, G_SWAP_BMP_SEL
267 MOV GS, AX ; GS: swap file bitmap
268 MOV EAX, ES:[EDI]
269 SHR EAX, 12 ; Block number
270 BTS DWORD PTR GS:[0], EAX ; Free swap file entry
271 JC SHORT $ ; Cannot happen
272FP_FREE1: MOV EAX, ES:[ESI] ; Get page table entry
273 TEST AX, PAGE_ALLOC ; Memory allocated?
274 JZ SHORT FP_ZERO ; No -> zero page table entry
275 SHR EAX, 12 ; Compute page number
276 CMP EAX, 4096*8 ; Address beyond bitmap (128M)?
277 JAE SHORT FP_KEEP ; Yes -> keep page table entry
278 CMP PAGE_BMAP_FLAG, FALSE ; Page bitmap enabled?
279 JE SHORT FP_KEEP ; No -> keep page table entry
280 INC FREED_PAGES ; One additional freed page
281 MOV BP, G_PAGE_BMP_SEL
282 MOV GS, BP ; GS: freed pages bitmap
283 BTS DWORD PTR GS:[0], EAX ; Free page
284 JC SHORT $ ; Cannot happen
285FP_ZERO: XOR EAX, EAX
286 MOV DWORD PTR ES:[EDI], EAX
287 MOV DWORD PTR ES:[ESI], EAX
288FP_NEXT_PAGE: ADD ESI, 4 ; Next entry
289 ADD EDI, 4
290 INC EBP ; Increment page number
291 LOOP FP_LOOP2 ; All page table entries
292FP_NEXT_TABLE: ADD EBX, 4 ; Next page table
293 CMP EBX, 4096 ; End of page directory?
294 JB FP_LOOP1 ; No -> repeat
295 CALL CLEAR_TLB ; Clear the TLB
296 POPAD
297 NOP ; Avoid 386 bug
298 POP GS
299 POP FS
300 POP ES
301 RET
302
303;
304; The physical address of the page is beyond 128M (ie, beyond the bitmap).
305; Let the swapper recycle this page. Unfortunately, this almost doesn't
306; work, as the PAGE_PRESENT bit is cleared as soon as new linear memory
307; is allocated (SET_PAGES). Nothing evil will happen, but memory beyond
308; 128M will almost never be reused.
309;
310FP_KEEP: MOV DWORD PTR ES:[EDI], SRC_NONE
311 AND DWORD PTR ES:[ESI], PAGE_PRESENT OR PAGE_ALLOC OR NOT 0FFFH
312 JMP SHORT FP_NEXT_PAGE
313
314FREE_PAGES ENDP
315
316
317;
318; Initialize bitmap for freed pages
319;
320 ASSUME DS:SV_DATA
321INIT_PAGE_BMAP PROC NEAR
322 MOV ECX, 4096
323 LEA SI, G_PAGE_BMP_DESC
324 CALL SV_SEGMENT
325 JC SHORT IPB_RET
326 MOV AX, G_PAGE_BMP_SEL
327 MOV ES, AX
328 MOV ECX, 4096 / 4
329 XOR EAX, EAX ; All pages used
330 XOR DI, DI
331 CLD
332 REP STOS DWORD PTR ES:[DI]
333 MOV PAGE_BMAP_FLAG, NOT FALSE
334IPB_RET: RET
335INIT_PAGE_BMAP ENDP
336
337;
338; Search bitmap for freed page
339;
340; Out: EAX Physical address of page (or NULL_PHYS if no page found)
341;
342 ASSUME DS:SV_DATA
343GET_FREE_PAGE PROC NEAR
344 MOV EAX, NULL_PHYS ; No page found
345 CMP FREED_PAGES, 0 ; Are there freed pages?
346 JE SHORT GFP_RET ; No -> done
347 PUSH ES
348 PUSH ECX
349 PUSH EDX
350 PUSH EDI
351 MOV AX, G_PAGE_BMP_SEL
352 MOV ES, AX
353 XOR EDI, EDI
354 MOV ECX, 4096 / 4
355 XOR EAX, EAX
356 CLD
357 REPE SCAS DWORD PTR ES:[EDI]
358 JE SHORT $ ; Cannot happen
359 BSF EAX, DWORD PTR ES:[EDI-4]
360 JZ SHORT $ ; Cannot happen
361 BTR ES:[EDI-4], EAX ; Clear bit (use page)
362 DEC FREED_PAGES ; Adjust counter
363 LEA EDX, [EDI-4]
364 SHL EDX, 3 ; 8 bits per byte
365 ADD EAX, EDX
366 SHL EAX, 12 ; Convert to physical address
367 POP EDI
368 POP EDX
369 POP ECX
370 POP ES
371GFP_RET: RET
372GET_FREE_PAGE ENDP
373
374
375;
376; Add the number of freed pages to TAVAIL
377;
378 ASSUME DS:SV_DATA
379FREE_AVAIL PROC NEAR
380 PUSH EAX
381 MOV EAX, FREED_PAGES
382 ADD TAVAIL, EAX
383 POP EAX
384 RET
385FREE_AVAIL ENDP
386
387
388;
389; Create page tables
390;
391; In: EAX Linear address
392; ECX Number of pages
393;
394; Out: CY=1 Out of memory
395;
396
397 ASSUME DS:SV_DATA
398
399INIT_PAGES PROC NEAR
400 PUSHAD
401 PUSH ES
402 PUSH FS
403 JECXZ SHORT IP_OK ; No pages -> done
404 MOV BX, G_PAGEDIR_SEL
405 MOV FS, BX
406 MOV BX, G_PHYS_SEL
407 MOV ES, BX ; Address page tables with ES
408 MOV EDI, EAX ; Bits 22..31 of linear addr.
409 SHR EDI, 22 ; EDI := page directory index
410 MOV EDX, EAX
411 SHR EDX, 12 ; Bits 12..21 of linear addr.
412 AND EDX, 03FFH ; Page table index
413;
414; EDI = page directory index
415; FS:0 = page directory
416; ECX = number of pages
417; EDX = page table index
418;
419IP_1: MOV EBX, FS:[4*EDI] ; Get page directory entry
420 OR EBX, EBX ; Does the entry exist?
421 JNZ SHORT IP_10 ; Yes -> use it
422 CALL PM_ALLOC ; Allocate swap table
423 CMP EAX, NULL_PHYS ; Out of memory?
424 JE SHORT IP_ERROR ; Yes -> error
425 CALL INIT_PAGE_TABLE ; Clear all entries
426 MOV FS:[4*EDI+4096], EAX ; Store address
427 CALL PM_ALLOC ; Allocate page table
428 CMP EAX, NULL_PHYS ; Out of memory?
429 JE SHORT IP_ERROR ; Yes -> error
430 CALL INIT_PAGE_TABLE ; Clear all entries
431 MOV EBX, EAX ; EBX := addr. of page table
432 OR EBX, PAGE_PRESENT OR PAGE_WRITE OR PAGE_USER
433 MOV FS:[4*EDI+0], EBX ; Make page directory entry
434IP_10: MOV EBX, 1024
435 SUB EBX, EDX ; Number of remaining entries
436 SUB ECX, EBX
437 JBE SHORT IP_OK
438 INC EDI ; Next page table
439 MOV EDX, 0 ; Page table index := 0
440 JMP SHORT IP_1
441
442IP_ERROR: STC ; Error return
443 JMP SHORT IP_RET
444
445IP_OK: CALL CLEAR_TLB ; Clear the TLB
446 CLC ; Ok
447IP_RET: POP FS
448 POP ES
449 POPAD
450 NOP ; Avoid 386 bug
451 RET
452INIT_PAGES ENDP
453
454
455
456
457;
458; Set page table entries
459;
460; The page tables must exist (cf. INIT_PAGES)!
461;
462; In: EAX Linear address
463; EBX Page table entry (if address != 0: autoincrement)
464; ECX Number of pages
465; EDX Swap table entry (if page number != 0: autoincrement)
466;
467; Out: CY Error (out of memory -- only if PAGE_ALLOC is set)
468;
469; The PAGE_ALLOC bit in EBX is handled specially. It tells SET_PAGES
470; to allocate memory or swap space for the pages.
471;
472
473
474 ASSUME DS:SV_DATA
475
476SET_PAGES PROC NEAR
477 PUSHAD ; Save registers
478 PUSH ES
479 PUSH FS
480 OR ECX, ECX
481 JZ SP_OK ; No pages -> done
482 MOV BP, G_PAGEDIR_SEL
483 MOV FS, BP
484 MOV BP, G_PHYS_SEL
485 MOV ES, BP ; Address page tables with ES
486 XCHG EAX, EBX ; EAX:=pt entry, EBX:=linear
487 MOV EBP, EBX ; Linear address
488 SHR EBP, 12
489 AND EBP, 03FFH ; EBP := page table index
490 SHR EBX, 22 ; EBX := page directory index
491;
492; FS:0 = pointer to page directory
493; EBX = page directory index
494; ES:ESI = pointer to page table entry
495; ES:EDI = pointer to swap table entry
496; EAX = page table entry (=:PTE)
497; ECX = number of pages
498; EDX = swap table entry
499; EBP = page table index
500;
501SP_1: MOV ESI, FS:[4*EBX+0] ; Get page directory entry
502 AND ESI, NOT 0FFFH ; Page table address
503 JZ SHORT $ ; Must not happen
504 MOV EDI, FS:[4*EBX+4096] ; Get pointer to swap table
505 OR EDI, EDI
506 JZ SHORT $ ; Must not happen
507SP_2: TEST AX, PAGE_ALLOC ; Allocate memory?
508 JNZ SHORT SP_MEM ; Yes -> allocate
509 TEST DX, SWAP_ALLOC ; Allocate swap space?
510 JNZ SHORT SP_SWAP ; Yes -> allocate
511SP_CONT: MOV ES:[ESI+4*EBP], EAX ; Store page table entry
512 MOV ES:[EDI+4*EBP], EDX ; Store swap table entry
513 DEC ECX ; Any pages left?
514 JZ SP_OK ; No -> done
515 TEST EAX, NOT 0FFFH ; Physical address = 0?
516 JZ SHORT SP_3 ; Yes -> skip
517 ADD EAX, 4096 ; No -> next physical address
518SP_3: TEST EDX, NOT 0FFFH ; Page number = 0?
519 JZ SHORT SP_4 ; Yes -> skip
520 ADD EDX, 4096 ; No -> next page number
521SP_4: INC EBP ; Increment page table index
522 CMP EBP, 1024 ; End of page table?
523 JB SHORT SP_2 ; No -> continue
524 INC EBX ; Next page table
525 XOR EBP, EBP ; First PTE of this table
526 JMP SHORT SP_1 ; New page table
527
528SP_MEM: AND EAX, 0FFFH ; Clear address
529 PUSH EAX ; Save page table entry
530 CALL PM_ALLOC_NOSWAP ; Allocate memory
531 CMP EAX, NULL_PHYS ; Success?
532 JE SHORT SP_MEM_FAIL ; No -> allocate swap space
533 OR EAX, [ESP] ; Insert address into PTE
534 ADD ESP, 4 ; Remove PTE from stack
535 JMP SP_CONT ; Store PTE
536
537SP_MEM_FAIL: POP EAX ; Restore page table entry
538 AND AX, NOT PAGE_ALLOC ; Stop allocating memory
539 OR DX, SWAP_ALLOC ; Allocate swap space instead
540SP_SWAP: PUSH EAX ; Save page table entry
541 CALL ALLOC_SWAP ; Allocate swap space
542 JC SHORT SP_FAIL ; No space -> error
543 AND EDX, 0FFFH ; Clear address
544 OR EDX, EAX ; Make swap table entry
545 POP EAX ; Restore page table entry
546 JMP SP_CONT ; Continue
547
548SP_FAIL: POP EAX ; Remove PTE from stack
549 ;...undo changes to page tables, deallocate
550 ; swap pages (not yet done)
551 STC
552 JMP SHORT SP_RET
553
554SP_OK: CLC
555SP_RET: CALL CLEAR_TLB ; Clear the TLB
556 POP FS ; Restore registers
557 POP ES
558 POPAD
559 NOP ; Avoid 386 bug
560 RET
561SET_PAGES ENDP
562
563
564;
565; Clear the dirty & accessed bits
566;
567; In: EAX Linear address
568; ECX Number of pages
569;
570 ASSUME DS:SV_DATA
571CLEAR_DIRTY PROC NEAR
572 PUSHAD ; Save registers
573 PUSH ES
574 PUSH FS
575 OR ECX, ECX
576 JZ CD_RET ; No pages -> done
577 MOV DX, G_PAGEDIR_SEL
578 MOV FS, DX
579 MOV DX, G_PHYS_SEL
580 MOV ES, DX ; Address page tables with ES
581 MOV EBX, EAX ; EBX:=linear address
582 MOV EDX, EBX ; Linear address
583 SHR EDX, 12
584 AND EDX, 03FFH ; EDX := page table index
585 SHR EBX, 22 ; EBX := page directory index
586;
587; FS:0 = pointer to page directory
588; EBX = page directory index
589; ES:ESI = pointer to page table entry
590; ECX = number of pages
591; EDX = page table index
592;
593CD_1: MOV ESI, FS:[4*EBX] ; Get page directory entry
594 AND ESI, NOT 0FFFH ; Page table address
595 JZ SHORT $ ; Must not happen
596CD_2: AND BYTE PTR ES:[ESI+4*EDX], NOT (PAGE_DIRTY+PAGE_ACCESSED)
597 DEC ECX ; Any pages left?
598 JZ CD_RET ; No -> done
599 INC EDX ; Increment page table index
600 CMP EDX, 1024 ; End of page table?
601 JB SHORT CD_2 ; No -> continue
602 INC EBX ; Next page table
603 XOR EDX, EDX ; First PTE of this table
604 JMP SHORT CD_1 ; New page table
605
606CD_RET: CALL CLEAR_TLB ; Clear the TLB
607 POP FS ; Restore registers
608 POP ES
609 POPAD
610 NOP ; Avoid 386 bug
611 RET
612CLEAR_DIRTY ENDP
613
614
615;
616; Clear the translation lookaside buffer
617;
618; Note: This procedure must not change the flags (see SET_PAGES).
619;
620CLEAR_TLB PROC NEAR
621 PUSH EAX
622 MOV EAX, CR3
623 MOV CR3, EAX ; This statement clears the TLB
624 POP EAX
625 RET
626CLEAR_TLB ENDP
627
628
629 ASSUME DS:NOTHING
630
631;
632; Initialize a page table (all pages not present)
633; Set 1024 DWORDs to 0
634;
635; In: ES:EAX Address of page table or swap table
636;
637INIT_PAGE_TABLE PROC NEAR
638 PUSH EAX
639 PUSH ECX
640 PUSH EDI
641 MOV EDI, EAX
642 MOV ECX, 1024 ; Number of DWORDs
643 XOR EAX, EAX
644 CLD
645 REP STOS DWORD PTR ES:[EDI]
646 POP EDI
647 POP ECX
648 POP EAX
649 RET
650INIT_PAGE_TABLE ENDP
651
652;
653; Create a page table for a page, if not already done, which maps
654; a page of physical memory below the LIN_START limit. This function
655; returns NULL_PHYS if the page is used for its own page table.
656;
657; In: EAX Physical address
658; EBX Linear address
659;
660; Out: EAX Physical address (or NULL_PHYS to repeat allocation)
661;
662 ASSUME DS:SV_DATA
663MAYBE_MAP_PAGE PROC NEAR
664 PUSH FS
665 PUSH EDX
666 CMP EAX, LIN_START ; Address valid in range?
667 JAE SHORT MMP_ERROR ; No -> must not happen
668 MOV DX, G_PAGEDIR_SEL ; Access page directory
669 MOV FS, DX ; at FS:0
670 MOV EDX, EBX ; Compute page directory index
671 SHR EDX, 22
672 CMP DWORD PTR FS:[4*EDX+0], 0 ; Page table initialized?
673 JE MMP_INIT ; No -> initialize
674MMP_RET: POP EDX
675 POP FS
676 RET
677
678MMP_ERROR: INT 3
679 JMP SHORT $
680
681;
682; Use the page as its own page table.
683;
684; First, use the temporary page for the page table to solve the
685; chicken and egg problem.
686;
687; As the linear address is smaller than LIN_START, there will be
688; no swap table, so one page is sufficient.
689;
690; In: EAX Physical address
691; EBX Linear address
692; EDX Page directory index
693; FS:0 Page directory
694
695MMP_INIT: PUSH ES
696 PUSH ECX
697 PUSH ESI
698 PUSH EDI
699
700 IF DEBUG_MAP
701 PUSH EDX
702 LEA EDX, $MMP1
703 CALL OTEXT
704 CALL ODWORD
705 LEA EDX, $MMP2
706 CALL OTEXT
707 XCHG EAX, EBX
708 CALL ODWORD
709 XCHG EAX, EBX
710 CALL OCRLF
711 POP EDX
712 ENDIF
713;
714; Zero the temporary page
715;
716 PUSH EAX
717 MOV AX, G_PHYS_SEL
718 MOV ES, AX
719 XOR EAX, EAX
720 MOV ECX, 1024
721 MOV EDI, TEMP_PAGE_PHYS
722 CLD
723 REP STOS DWORD PTR ES:[EDI]
724 POP EAX
725;
726; Set all the page table entries, including the one which points
727; to the target page. This assumes that LIN_START points to a
728; 4 MB (page table) boundary.
729;
730 PUSH EAX
731 MOV EDI, TEMP_PAGE_PHYS
732 MOV ESI, EBX ; Linear address
733 SHR ESI, 12
734 AND ESI, 03FFH ; Page table index MOV EDX, EAX ; EDX := physical address
735 SHL ESI, 10 ; Relative physical address
736 SUB EAX, ESI ; First physical address
737 OR EAX, PAGE_PRESENT OR PAGE_WRITE OR PAGE_USER
738 MOV ECX, 1024
739 TALIGN 4
740MMPI_1: STOS DWORD PTR ES:[EDI]
741 ADD EAX, 4096
742 LOOP MMPI_1
743 POP EAX
744;
745; Set the page directory entry to point to the temporary page
746;
747 MOV ECX, TEMP_PAGE_PHYS
748 OR ECX, PAGE_PRESENT OR PAGE_WRITE OR PAGE_USER
749 MOV FS:[4*EDX+0], ECX
750 CALL CLEAR_TLB
751;
752; Now, the page is accessible and we can copy the temporary page,
753; which is simpler than initializing it from scrach
754;
755 MOV ESI, TEMP_PAGE_PHYS
756 MOV EDI, EAX ; Physical address
757 MOV ECX, 1024
758 PUSH DS
759 MOV_DS_ES
760 ASSUME DS:NOTHING
761 REP MOVS DWORD PTR ES:[EDI], DWORD PTR DS:[ESI]
762 POP DS
763 ASSUME DS:SV_DATA
764;
765; Finally, we let the page directory point to the new page
766;
767 MOV ECX, EAX ; Physical address
768 OR ECX, PAGE_PRESENT OR PAGE_WRITE OR PAGE_USER
769 MOV FS:[4*EDX+0], ECX
770 CALL CLEAR_TLB
771 POP EDI
772 POP ESI
773 POP ECX
774 POP ES
775 MOV EAX, NULL_PHYS
776 JMP MMP_RET
777MAYBE_MAP_PAGE ENDP
778
779SV_CODE ENDS
780
781
782
783INIT_CODE SEGMENT
784
785 ASSUME CS:INIT_CODE, DS:NOTHING
786
787;
788; Initialize paging
789;
790 ASSUME DS:SV_DATA
791
792INIT_PAGING PROC NEAR
793 MOV AX, 1
794 CALL RM_ALLOC ; Allocate linear address map
795 CMP AX, NULL_RM ; Out of memory?
796 JE RM_OUT_OF_MEM ; Yes -> abort
797 MOV LIN_MAP_SEG, AX ; Save segment
798
799 MOV AX, 2 ; Allocate page directory
800 CALL RM_ALLOC ; and swap directory
801 CMP AX, NULL_RM ; Out of memory?
802 JE RM_OUT_OF_MEM ; Yes -> abort
803 MOV PAGE_DIR_SEG, AX ; Save segment
804 MOV ES, AX
805 MOV EAX, 0 ; Zero page directory and
806 MOV DI, 0 ; swap directory
807 CLD
808 MOV ECX, 2*1024
809 REP STOS DWORD PTR ES:[DI]
810
811 CMP VCPI_FLAG, FALSE ; VCPI?
812 JE SHORT IPG_1 ; No -> setup page tables
813 CALL INIT_VCPI ; Special handling for VCPI
814 JMP SHORT IPG_2 ; Continue
815
816IPG_1: MOV FS, PAGE_DIR_SEG
817 MOV SI, 0 ; FS:SI = pointer to page dir
818 MOV CX, 1 ; 1 page table (4 MB)
819 MOV EBP, 0 ; Address = 0
820 CALL MAP_PAGES
821 .ERRE MAX_PHYS_MEM GE 4 ; At least one page table
822 .ERRE MAX_PHYS_MEM LE 2048 ; No point in having more
823 .ERRNZ MAX_PHYS_MEM MOD 4
824 MOV ECX, MAX_PHYS_MEM * 1024 * 1024
825 MOV LIN_START, ECX ; First unused linear address
826 LEA DI, G_PHYS_DESC
827 CALL RM_SEG_SIZE
828
829IPG_2: MOV AX, PAGE_DIR_SEG
830 XOR DX, DX
831 CALL RM_TO_PHYS
832 MOV PAGE_DIR_PHYS, EAX
833 MOV V2P_CR3, EAX ; For VCPI
834 MOV TSS_EX8_CR3, EAX ; CR3 for exception 8
835 MOV TSS_EX10_CR3, EAX ; CR3 for exception 10
836
837 MOVZX EAX, PAGE_DIR_SEG
838 SHL EAX, 4
839 LEA DI, G_PAGEDIR_DESC
840 CALL RM_SEG_BASE
841 MOVZX EAX, LIN_MAP_SEG
842 SHL EAX, 4
843 LEA DI, G_LIN_MAP_DESC
844 CALL RM_SEG_BASE
845;
846; Allocate a page to be used as temporary page table during memory
847; allocation
848;
849 MOV AX, 1
850 CALL RM_ALLOC
851 CMP AX, NULL_RM ; Out of memory?
852 JE RM_OUT_OF_MEM ; Yes -> abort
853 MOV TEMP_PAGE_SEG, AX ; Save segment
854 MOV DX, 0
855 CALL RM_TO_PHYS
856 MOV TEMP_PAGE_PHYS, EAX ; Save physical address
857 RET
858INIT_PAGING ENDP
859
860
861
862;
863; Map pages (called in real mode)
864;
865; This function creates only complete page tables (for simplicity)
866; Uses RM_TO_PHYS
867;
868; In: CX Number of page tables
869; EBP Physical address
870; FS:SI Pointer to page directory entry
871;
872; Out: EBP Next physical address
873; FS:SI Pointer to next page directory entry
874;
875; Note: Successive calls initialize successive page tables.
876;
877MAP_PAGES PROC NEAR
878 PUSH DX
879MP_OUTER_LOOP: PUSH CX ; Save page table counter
880 MOV AX, 1 ; Allocate a page table
881 CALL RM_ALLOC
882 CMP AX, NULL_RM ; Out of memory?
883 JE RM_OUT_OF_MEM ; Yes -> abort
884 PUSH AX ; Save segment
885 XOR DX, DX ; Offset = 0
886 CALL RM_TO_PHYS ; Get physical address
887 OR EAX, PAGE_PRESENT OR PAGE_WRITE OR PAGE_USER
888 MOV FS:[SI], EAX ; Store page directory entry
889 ADD SI, 4 ; Next page directory entry
890 POP ES
891 MOV EAX, EBP ; Get entry/address
892 OR EAX, PAGE_PRESENT OR PAGE_WRITE OR PAGE_USER
893 MOV CX, 1024 ; Initialize 1024 entries
894 MOV DI, 0
895MP_INNER_LOOP: STOS DWORD PTR ES:[DI] ; Store page table entry
896 ADD EAX, 4096 ; Next page
897 LOOP MP_INNER_LOOP ; Initialize all table entries
898 ADD EBP, 4096*1024 ; Save entry/address
899 POP CX ; Restore page table counter
900 LOOP MP_OUTER_LOOP ; Create all page tables
901 POP DX
902 RET
903MAP_PAGES ENDP
904
905
906;
907; Convert a real-mode address to the physical address
908;
909; In: AX Real-mode segment
910; DX Real-mode offset
911;
912; Out: EAX Physical address
913; EDX Upper word cleared
914;
915 ASSUME DS:SV_DATA
916RM_TO_PHYS PROC NEAR
917 MOVZX EAX, AX ; Clear upper word
918 MOVZX EDX, DX ; Clear upper word
919 SHL EAX, 4 ; Compute linear address
920 ADD EAX, EDX
921 CMP VCPI_FLAG, FALSE ; VCPI active?
922 JE SHORT RTP_RET ; No -> physical = linear
923 CALL VCPI_LIN_TO_PHYS
924RTP_RET: RET
925
926RM_TO_PHYS ENDP
927
928
929INIT_CODE ENDS
930
931 END
Note: See TracBrowser for help on using the repository browser.