4 ;******************************************************************************
5 title VDM_Init
- VDM initialization module
6 ;******************************************************************************
8 ; (C) Copyright MICROSOFT Corp. 1986
10 ; Title: MEMM.EXE - MICROSOFT Expanded Memory Manager 386 Driver
12 ; Module: VDM_Init - VDM initialization routine
20 ;******************************************************************************
24 ; DATE REVISION DESCRIPTION
25 ; -------- -------- -------------------------------------------------------
26 ; 06/03/86 Original from VDM MAIN.ASM module
27 ; 06/16/86 0.01 Added code to dword align LL buffer
28 ; 06/21/86 0.02 moved cld in init_pages
29 ; 06/28/86 0.02 Name change from MEMM386 to MEMM
30 ; 07/06/86 0.04 changed assume to DGROUP and moved stack out of
32 ; 07/10/86 0.05 Init of RCODEA_GSEL
33 ; 07/10/86 0.05 Added PageT_Seg
34 ; 07/20/88 Removed debugger codes (pc)
36 ;******************************************************************************
38 ; Functional Description:
40 ; This module is the general initialization module for the Virtual DOS
41 ; Monitor part of MEMM. This module initializes the protected mode
42 ; GDT, IDT, TSS (and I/O BitMap), and the Page Tables. This module also
43 ; initializes all variables used by the VDM code. This module returns
44 ; to the calling routine in Virtual Mode.
46 ;******************************************************************************
47 .lfcond
; list false conditionals
49 ;******************************************************************************
51 ;******************************************************************************
58 ;******************************************************************************
60 ;******************************************************************************
72 ;******************************************************************************
73 ; E X T E R N A L R E F E R E N C E S
74 ;******************************************************************************
77 extrn ELOff
:word ; offset of LL buffer
82 extrn InitBitMap
:far ; (vminit.asm)
104 extrn SetSegDesc
:near
106 extrn SetPageEntry
:near
107 extrn get_init_a20_state
:near
108 extrn OEM_Init_Diag_Page
:near
111 ;******************************************************************************
112 ; S E G M E N T D E F I N I T I O N S
113 ;******************************************************************************
116 ; Ring 0 stack for VDM exception/int handling
121 db STACK0_SIZE
dup(0)
124 kstack_top
label byte
134 PageD_Seg dw 0 ; segment for Page Directory
135 PageT_Seg dw 0 ; segment for Page Tables
136 Page_Dir dd 0 ; 32 bit address of Page Directory
145 assume
cs:LAST
, ds:DGROUP
, es:DGROUP
147 ;******************************************************************************
148 ; VDM_Init - VDM initialization routine
157 ; VDM Tables initialized
162 ;******************************************************************************
176 call InitGdt
;;; initialize GDT descriptors
178 ; initialize Page Table, I/O Bit Map and LIM h/w emulator
180 call InitPages
;;; initialize paging tables
181 call InitBitMap
;;; initialize I/O Bit Map
183 ; initialize TSS,GDTR,IDTR
185 ; set ring 0 SS:SP in the TSS so we can take outer ring traps
188 mov es,ax ; ES -> TSS
189 xor di,di ; ES:DI -> TSS
191 mov ES:[di.TSS386_SS0
], VDMS_GSEL
192 mov word ptr ES:[di.TSS386_ESP0lo
], offset
STACK:kstack_top
193 mov word ptr ES:[di.TSS386_ESP0hi
], 0
195 ; now set CR3 in the TSS
198 mov ax,word ptr [Page_Dir
] ; EAX = page dir 32 bit addr
200 mov word ptr ES:[di.TSS386_CR3
],ax ; mov EAX into CR3 spot in TSS
202 ; clear the TSS busy flag
205 mov es, ax ; DS:0 = ptr to gdt
207 and byte ptr ES:[TSS_GSEL
+ 5], 11111101B
210 ; dword align the LL buffer (move foward)
215 sub bx,ax ; BX = amount to add to dword align
216 add [ELOff
],bx ; dword align it...
229 ;** InitGdt - initialise GDT
231 ; Some of the GDT is statically initialised. This routine
232 ; initialises the rest, except the LDT pointer which
233 ; changes dynamically, and the VDM stack which changes too.
235 ; ENTRY GDT:0 = GDT to use.
239 ; WARNING This code only works on a 286.
240 ; Designed to be called from real mode ONLY.
247 mov es,ax ; ES:0 -> gdt
254 call SetSegDesc
; Set up GDT alias descriptor
261 call SetSegDesc
; Set up IDT alias descriptor
268 call SetSegDesc
; Set up TSS descriptor
272 call SetSegDesc
; Set up TSS alias descriptor
276 mov cx,0 ; 0 = 64K size
279 call SetSegDesc
; Set up VDM Code descriptor
283 mov cx,0 ; 0 = 64K size
286 call SetSegDesc
; Set up VDM Code segment alias descr
290 mov cx,0 ; 0 = 64K size
293 call SetSegDesc
; Set up R_CODE segment alias descriptor
297 mov cx,0 ; 0 = 64K size
300 call SetSegDesc
; Set up VDM Data descriptor
302 mov ax, seg
STACK ; set up Ring 0 stack
304 mov cx, offset
STACK:kstack_top
313 ;** InitPages - initialize Page Directory and Table
315 ; This routine initializes a page directory and a page table.
316 ; Both of these are aligned on a physical page boundary by
317 ; starting them at the nearest bndry. Thus, the page table area
318 ; must be large enough to allow this alignment.
320 ; The page dir and table set up by this routine maps the linear
321 ; addresses for Virtual mode programs into physical addresses using
322 ; the following scheme.
323 ; Linear Addr Physical Addr
324 ; 00000000h - 000FFFFFh 00000000h - 000FFFFFh
325 ; 00100000h - 0010FFFFh 00000000h - 0000FFFFh (64k wraparound)
326 ; 00110000h - 0100FFFFh 00100000h - 00FFFFFFh (top 15Meg of phys)
328 ; ISP,PC: The above was totally unnecessary. When the A20 is turned
329 ; off the 64k at 1M is anyway unaccessible. A better mapping
330 ; has been implemented here:
332 ; Linear Addr Physical Addr
333 ; 00000000h - 000FFFFFh 00000000h - 000FFFFFh
334 ; 00100000h - 0010FFFFh 00000000h - 0000FFFFh (64k wraparound)
335 ; 00110000h - 01000000h 00110000h - 01000000h (top 15Meg of phys)
336 ; 01000000h - 0100ffffh xxxx0000h - xxxxffffh (Done in OEMPROC)
339 ; ENTRY PAGESEG:Page_Area = pointer to page table area.
341 ; EXIT DS:PageD_Seg = seg ptr for page directory.
342 ; DS:PageT_Seg = seg ptr for page tables
343 ; DS:Page_Dir = 32 bit addr for page directory.
346 ; WARNING This code only works on a 286/386.
347 ; Designed to be called from real mode ONLY.
359 ; get physical pointer to nearest page
361 mov ax,offset PAGESEG
:Page_Area
363 shr ax,4 ; AX = seg offset for page area
364 mov bx,PAGESEG
; PAGESEG is on a 256 boundary
365 add ax,bx ; AX = seg offset for page area
366 add ax,0FFh ; 0FFh = # of paras in page - 1
367 xor al,al ; AX = seg addr for page align
368 mov [PageD_Seg
],ax ; save it
371 mov es,ax ; ES:DI = ptr to Page Directory
374 shr dl,4 ; DL = bits 16 - 19
375 xor dh,dh ; DX = bits 16 - 31
376 shl ah,4 ; AX = bits 0 - 15
377 mov word ptr [Page_Dir
],AX ; DX,AX = 32 bit addr of Page Directory
378 mov word ptr [Page_Dir
+2],DX ; save it
380 ; get addr of Page Table for Page Directory entry
382 add ax,1000h
; add page
383 adc dx,0h
; carry it => DX,AX = addr of page table
385 ; set entries in page directory
387 ; ES:[DI] pts to first entry in page directory
388 ; DX,AX = addr of first page table
391 mov bl,P_AVAIL
; make table available to all
392 mov cx,P_TABLE_CNT
; set entries in page table directory
393 ; for existing page tables.
395 call SetPageEntry
; set entry for first page table
397 ; ES:[DI] pts to next entry in page directory
399 adc dx,0 ; DX,AX = addr of next page table
400 loop init_dir
; set next entry in dir
402 ; set rest of entries in page directory to not present
404 mov bl,NOT P_PRES
; mark page table as not present
406 sub cx,P_TABLE_CNT
; set rest of entries in directory
411 ; set entries in page tables
414 ; Linear Addr Physical Addr
415 ; 00000000h - 000FFFFFh 00000000h - 000FFFFFh
417 mov ax,[PageD_Seg
] ; get segment for page directory
418 add ax,0100h ; add 1 page to get to first page table
419 mov [PageT_Seg
],ax ; save it
422 xor di,di ; ES:[DI] pts to first page table
425 xor ax,ax ; start with physical addr = 00000000h
427 mov bl,P_AVAIL
; make pages available to all
428 mov cx,100h
; set 1 Meg worth of entries in table
431 ; ES:[DI] pts to next page table entry
432 add ax,1000h
; next physical page
433 adc dx,0h
; address in DX,AX
434 loop set1_tentry
;Q: done with this page table
436 ; Y: set next entries in next tables
437 ; 64k wraparound at 1.0 Meg
438 ; Linear Addr Physical Addr
439 ; 00100000h - 0010FFFFh 00000000h - 0000FFFFh (64k wraparound)
441 call get_init_a20_state
; the physical a20 state has already
445 xor ax,ax ; start with physical addr = 00000000h
448 mov bl,P_AVAIL
; make pages available to all
449 mov cx,10h
; set 64k worth of entries
452 ; ES:[DI] pts to next page table entry
453 add ax,1000h
; next physical page
454 adc dx,0h
; address in DX,AX
455 loop set2_tentry
;Q: done with the wraparound entries
459 ; last (15M - 64K) of linear addresses ( for Move Block/Loadall )
460 ; Linear Addr Physical Addr
461 ; 00110000h - 01000000h 00110000h - 01000000h
464 xor ax,ax ; start with 00110000h physical
466 mov bl,P_AVAIL
; make pages available to all
467 mov cx,(4*400h
)-100h
-10h
; (15M-64K) worth of Page Table Entries
470 ; ES:[DI] pts to next page table entry
471 add ax,1000h
; next physical page
472 adc dx,0h
; address in DX,AX
473 loop set3_tentry
;Q: done with last entries
478 ; fill out entries in last table as not present
483 mov bl,0 ; page not present
485 ; we can actually forget about this last page table because we
486 ; are not going to use them
488 mov cx,400h
; last table
490 call SetPageEntry
; set this entry
493 ; our honorable OEM Compaq has to be supported, so we have this hook into
494 ; OEMPROC to modify the last page table to point at the diagnostics segment
496 call OEM_Init_Diag_Page
498 ; all done with page dir and table setup
499 ; set up page directory and page table selectors
502 mov es,ax ; ES pts to GDT
504 mov ax,[PageT_Seg
] ; seg for page tables
506 mov cx,0 ; enough room for tables
509 call SetSegDesc
; set up page tables entry