]> wirehaze git hosting - MS-DOS.git/blob - v4.0/src/MEMM/MEMM/VDMINIT.ASM

wirehaze git hosting

MZ is back!
[MS-DOS.git] / v4.0 / src / MEMM / MEMM / VDMINIT.ASM
1
2
3 page 58,132
4 ;******************************************************************************
5 title VDM_Init - VDM initialization module
6 ;******************************************************************************
7 ;
8 ; (C) Copyright MICROSOFT Corp. 1986
9 ;
10 ; Title: MEMM.EXE - MICROSOFT Expanded Memory Manager 386 Driver
11 ;
12 ; Module: VDM_Init - VDM initialization routine
13 ;
14 ; Version: 0.05
15 ;
16 ; Date: June 3,1986
17 ;
18 ; Author:
19 ;
20 ;******************************************************************************
21 ;
22 ; Change log:
23 ;
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
31 ; DGROUP
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)
35 ;
36 ;******************************************************************************
37 ;
38 ; Functional Description:
39 ;
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.
45 ;
46 ;******************************************************************************
47 .lfcond ; list false conditionals
48 .386p
49 ;******************************************************************************
50 ; P U B L I C S
51 ;******************************************************************************
52
53 public VDM_Init
54 public PageD_Seg
55 public PageT_Seg
56 public Page_Dir
57
58 ;******************************************************************************
59 ; D E F I N E S
60 ;******************************************************************************
61 include VDMseg.inc
62 include VDMsel.inc
63 include desc.inc
64 include instr386.inc
65 include page.inc
66
67 FALSE equ 0
68 TRUE equ not FALSE
69 CR equ 0dh
70 LF equ 0ah
71
72 ;******************************************************************************
73 ; E X T E R N A L R E F E R E N C E S
74 ;******************************************************************************
75 _DATA SEGMENT
76 extrn P_TABLE_CNT:abs
77 extrn ELOff:word ; offset of LL buffer
78 _DATA ENDS
79
80 _TEXT SEGMENT
81
82 extrn InitBitMap:far ; (vminit.asm)
83
84 _TEXT ENDS
85
86 GDT SEGMENT
87 extrn GDTLEN:abs
88 GDT ENDS
89
90 IDT SEGMENT
91 extrn IDTLEN:abs
92 IDT ENDS
93
94 TSS SEGMENT
95 extrn TSSLEN:abs
96 TSS ENDS
97
98 PAGESEG SEGMENT
99 extrn Page_Area:byte
100 PAGESEG ENDS
101
102
103 LAST SEGMENT
104 extrn SetSegDesc:near
105 extrn SegTo24:near
106 extrn SetPageEntry:near
107 extrn get_init_a20_state:near
108 extrn OEM_Init_Diag_Page:near
109 LAST ENDS
110
111 ;******************************************************************************
112 ; S E G M E N T D E F I N I T I O N S
113 ;******************************************************************************
114
115 ;
116 ; Ring 0 stack for VDM exception/int handling
117 ;
118 STACK SEGMENT
119 stkstrt label byte
120
121 db STACK0_SIZE dup(0)
122
123 public kstack_top
124 kstack_top label byte
125
126 db 400h dup (0)
127 public exe_stack
128 exe_stack label byte
129
130 STACK ENDS
131
132 _DATA SEGMENT
133
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
137
138 _DATA ENDS
139
140 ;
141 ; code
142 ;
143 LAST SEGMENT
144
145 assume cs:LAST, ds:DGROUP, es:DGROUP
146
147 ;******************************************************************************
148 ; VDM_Init - VDM initialization routine
149 ;
150 ;
151 ; ENTRY: Real Mode
152 ; DS = DGROUP
153 ; GDT = GDT segment
154 ; TSS = TSS segment
155 ;
156 ; EXIT: Real Mode
157 ; VDM Tables initialized
158 ; TSS initialized
159 ;
160 ; USED: none
161 ;
162 ;******************************************************************************
163 VDM_Init proc near
164 ;
165 pushf
166 pusha
167 PUSH_EAX
168 push ds
169 push es
170 ;
171 push ds
172 pop es ; ES = data
173 ;
174 cli
175 ;
176 call InitGdt ;;; initialize GDT descriptors
177 ;
178 ; initialize Page Table, I/O Bit Map and LIM h/w emulator
179 ;
180 call InitPages ;;; initialize paging tables
181 call InitBitMap ;;; initialize I/O Bit Map
182 ;
183 ; initialize TSS,GDTR,IDTR
184 ;
185 ; set ring 0 SS:SP in the TSS so we can take outer ring traps
186
187 mov ax, seg TSS
188 mov es,ax ; ES -> TSS
189 xor di,di ; ES:DI -> TSS
190
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
194
195 ; now set CR3 in the TSS
196
197 db 66h
198 mov ax,word ptr [Page_Dir] ; EAX = page dir 32 bit addr
199 db 66h
200 mov word ptr ES:[di.TSS386_CR3],ax ; mov EAX into CR3 spot in TSS
201
202 ; clear the TSS busy flag
203
204 mov ax,seg GDT
205 mov es, ax ; DS:0 = ptr to gdt
206
207 and byte ptr ES:[TSS_GSEL + 5], 11111101B
208
209 ;
210 ; dword align the LL buffer (move foward)
211 ;
212 mov ax,[ELOff]
213 and ax,0003h ; MOD 4
214 mov bx,4
215 sub bx,ax ; BX = amount to add to dword align
216 add [ELOff],bx ; dword align it...
217
218 ;
219 ; and return
220 ;
221 pop es
222 pop ds
223 POP_EAX
224 popa
225 popf
226 ret
227 VDM_Init endp
228
229 ;** InitGdt - initialise GDT
230 ;
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.
234 ;
235 ; ENTRY GDT:0 = GDT to use.
236 ; EXIT None
237 ; USES All except BP
238 ;
239 ; WARNING This code only works on a 286.
240 ; Designed to be called from real mode ONLY.
241
242 public InitGdt
243 InitGdt proc near
244 push es
245
246 mov ax,GDT
247 mov es,ax ; ES:0 -> gdt
248
249 mov ax,GDT
250 call SegTo24
251 mov cx,GDTLEN
252 mov ah,D_DATA0
253 mov bx,GDTD_GSEL
254 call SetSegDesc ; Set up GDT alias descriptor
255
256 mov ax,IDT
257 call SegTo24
258 mov cx,IDTLEN
259 mov ah,D_DATA0
260 mov bx,IDTD_GSEL
261 call SetSegDesc ; Set up IDT alias descriptor
262
263 mov ax,TSS
264 call SegTo24
265 mov cx,TSSLEN
266 mov ah,D_386TSS0
267 mov bx,TSS_GSEL
268 call SetSegDesc ; Set up TSS descriptor
269
270 mov ah,D_DATA0
271 mov bx,TSSD_GSEL
272 call SetSegDesc ; Set up TSS alias descriptor
273
274 mov ax,seg _TEXT
275 call SegTo24
276 mov cx,0 ; 0 = 64K size
277 mov ah,D_CODE0
278 mov bx,VDMC_GSEL
279 call SetSegDesc ; Set up VDM Code descriptor
280
281 mov ax,_TEXT
282 call SegTo24
283 mov cx,0 ; 0 = 64K size
284 mov ah,D_DATA0
285 mov bx,VDMCA_GSEL
286 call SetSegDesc ; Set up VDM Code segment alias descr
287
288 mov ax,R_CODE
289 call SegTo24
290 mov cx,0 ; 0 = 64K size
291 mov ah,D_DATA0
292 mov bx,RCODEA_GSEL
293 call SetSegDesc ; Set up R_CODE segment alias descriptor
294
295 mov ax,seg DGROUP
296 call SegTo24
297 mov cx,0 ; 0 = 64K size
298 mov ah,D_DATA0
299 mov bx,VDMD_GSEL
300 call SetSegDesc ; Set up VDM Data descriptor
301
302 mov ax, seg STACK ; set up Ring 0 stack
303 call SegTo24
304 mov cx, offset STACK:kstack_top
305 mov ah, D_DATA0
306 mov bx, VDMS_GSEL
307 call SetSegDesc
308
309 pop es
310 ret
311 InitGdt endp
312
313 ;** InitPages - initialize Page Directory and Table
314 ;
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.
319 ;
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)
327 ;
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:
331 ;
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)
337 ;
338 ;
339 ; ENTRY PAGESEG:Page_Area = pointer to page table area.
340 ; DS = DGROUP
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.
344 ; USES none
345 ;
346 ; WARNING This code only works on a 286/386.
347 ; Designed to be called from real mode ONLY.
348
349 public InitPages
350 InitPages proc near
351 push ax
352 push bx
353 push cx
354 push dx
355 push di
356 push es
357 cld ; strings foward
358 ;
359 ; get physical pointer to nearest page
360 ;
361 mov ax,offset PAGESEG:Page_Area
362 add ax,15
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
369 ;
370 xor di,di
371 mov es,ax ; ES:DI = ptr to Page Directory
372 ;
373 mov dl,ah
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
379 ;
380 ; get addr of Page Table for Page Directory entry
381 ;
382 add ax,1000h ; add page
383 adc dx,0h ; carry it => DX,AX = addr of page table
384 ;
385 ; set entries in page directory
386 ;
387 ; ES:[DI] pts to first entry in page directory
388 ; DX,AX = addr of first page table
389 ;
390 mov bh,0
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.
394 init_dir:
395 call SetPageEntry ; set entry for first page table
396 ;
397 ; ES:[DI] pts to next entry in page directory
398 add ax,1000h
399 adc dx,0 ; DX,AX = addr of next page table
400 loop init_dir ; set next entry in dir
401 ;
402 ; set rest of entries in page directory to not present
403 mov bh,0
404 mov bl,NOT P_PRES ; mark page table as not present
405 mov cx,400h
406 sub cx,P_TABLE_CNT ; set rest of entries in directory
407 set_dir:
408 call SetPageEntry
409 loop set_dir
410 ;
411 ; set entries in page tables
412 ;
413 ; first 1 Meg
414 ; Linear Addr Physical Addr
415 ; 00000000h - 000FFFFFh 00000000h - 000FFFFFh
416 ;
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
420
421 mov es,ax
422 xor di,di ; ES:[DI] pts to first page table
423
424 xor dx,dx
425 xor ax,ax ; start with physical addr = 00000000h
426 mov bh,0
427 mov bl,P_AVAIL ; make pages available to all
428 mov cx,100h ; set 1 Meg worth of entries in table
429 set1_tentry:
430 call SetPageEntry
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
435 ; N: the loop again
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)
440 ;
441 call get_init_a20_state ; the physical a20 state has already
442 ; been established
443 jnz skip_wrap
444 xor dx,dx
445 xor ax,ax ; start with physical addr = 00000000h
446 skip_wrap:
447 mov bh,0
448 mov bl,P_AVAIL ; make pages available to all
449 mov cx,10h ; set 64k worth of entries
450 set2_tentry:
451 call SetPageEntry
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
456 ; N: loop again
457 ; Y: all done
458 ;
459 ; last (15M - 64K) of linear addresses ( for Move Block/Loadall )
460 ; Linear Addr Physical Addr
461 ; 00110000h - 01000000h 00110000h - 01000000h
462 ;
463 mov dx,0011h
464 xor ax,ax ; start with 00110000h physical
465 mov bh,0
466 mov bl,P_AVAIL ; make pages available to all
467 mov cx,(4*400h)-100h-10h ; (15M-64K) worth of Page Table Entries
468 set3_tentry:
469 call SetPageEntry
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
474 ; N: loop again
475 ; Y: all done
476
477 ;
478 ; fill out entries in last table as not present
479 ;
480 xor ax,ax
481 xor dx,dx ; addr = 0
482 mov bh,0
483 mov bl,0 ; page not present
484 ;
485 ; we can actually forget about this last page table because we
486 ; are not going to use them
487 ;
488 mov cx,400h ; last table
489 setL_tentry:
490 call SetPageEntry ; set this entry
491 loop setL_tentry
492 ;
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
495 ;
496 call OEM_Init_Diag_Page
497 ;
498 ; all done with page dir and table setup
499 ; set up page directory and page table selectors
500 ;
501 mov ax,seg GDT
502 mov es,ax ; ES pts to GDT
503
504 mov ax,[PageT_Seg] ; seg for page tables
505 call SegTo24
506 mov cx,0 ; enough room for tables
507 mov ah,D_DATA0
508 mov bx,PAGET_GSEL
509 call SetSegDesc ; set up page tables entry
510
511 ;
512 ; EXIT
513 ;
514 pop es
515 pop di
516 pop dx
517 pop cx
518 pop bx
519 pop ax
520 ret
521 InitPages endp
522
523 LAST ends
524
525 END
526 \1a
527 \1a