]> git.kernelconcepts.de Git - karo-tx-uboot.git/blob - board/MAI/bios_emulator/scitech/src/pm/smx/_vflat.asm
* Patch by Thomas Frieden, 13 Nov 2002:
[karo-tx-uboot.git] / board / MAI / bios_emulator / scitech / src / pm / smx / _vflat.asm
1 ;****************************************************************************
2 ;*
3 ;*                  SciTech OS Portability Manager Library
4 ;*
5 ;*  ========================================================================
6 ;*
7 ;*    The contents of this file are subject to the SciTech MGL Public
8 ;*    License Version 1.0 (the "License"); you may not use this file
9 ;*    except in compliance with the License. You may obtain a copy of
10 ;*    the License at http://www.scitechsoft.com/mgl-license.txt
11 ;*
12 ;*    Software distributed under the License is distributed on an
13 ;*    "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
14 ;*    implied. See the License for the specific language governing
15 ;*    rights and limitations under the License.
16 ;*
17 ;*    The Original Code is Copyright (C) 1991-1998 SciTech Software, Inc.
18 ;*
19 ;*    The Initial Developer of the Original Code is SciTech Software, Inc.
20 ;*    All Rights Reserved.
21 ;*
22 ;*  ========================================================================
23 ;*
24 ;*            Based on original code Copyright 1994 Otto Chrons
25 ;*
26 ;* Language:    80386 Assembler, TASM 4.0 or later
27 ;* Environment: IBM PC 32 bit protected mode
28 ;*
29 ;* Description: Low level page fault handler for virtual linear framebuffers.
30 ;*
31 ;****************************************************************************
32
33         IDEAL
34         JUMPS
35
36 include "scitech.mac"           ; Memory model macros
37
38 header      _vflat              ; Set up memory model
39
40 VFLAT_START     EQU 0F0000000h
41 VFLAT_END       EQU 0F03FFFFFh
42 PAGE_PRESENT    EQU 1
43 PAGE_NOTPRESENT EQU 0
44 PAGE_READ       EQU 0
45 PAGE_WRITE      EQU 2
46
47 ifdef   DOS4GW
48
49 ;----------------------------------------------------------------------------
50 ; DOS4G/W flat linear framebuffer emulation.
51 ;----------------------------------------------------------------------------
52
53 begdataseg  _vflat
54
55 ; Near pointers to the page directory base and our page tables. All of
56 ; this memory is always located in the first Mb of DOS memory.
57
58 PDBR            dd  0               ; Page directory base register (CR3)
59 accessPageAddr  dd  0
60 accessPageTable dd  0
61
62 ; CauseWay page directory & 1st page table linear addresses.
63
64 CauseWayDIRLinear dd 0
65 CauseWay1stLinear dd 0
66
67 ; Place to store a copy of the original Page Table Directory before we
68 ; intialised our virtual buffer code.
69
70 pageDirectory:  resd 1024           ; Saved page table directory
71
72 ValidCS         dw  0               ; Valid CS for page faults
73 Ring0CS         dw  0               ; Our ring 0 code selector
74 LastPage        dd  0               ; Last page we mapped in
75 BankFuncBuf:    resb 101            ; Place to store bank switch code
76 BankFuncPtr     dd  offset BankFuncBuf
77
78 INT14Gate:
79 INT14Offset     dd      0           ; eip of original vector
80 INT14Selector   dw      0           ; cs of original vector
81
82         cextern _PM_savedDS,USHORT
83         cextern VF_haveCauseWay,BOOL
84
85 enddataseg  _vflat
86
87 begcodeseg  _vflat              ; Start of code segment
88
89         cextern VF_malloc,FPTR
90
91 ;----------------------------------------------------------------------------
92 ; PF_handler64k - Page fault handler for 64k banks
93 ;----------------------------------------------------------------------------
94 ; The handler below is a 32 bit ring 0 page fault handler.  It receives
95 ; control immediately after any page fault or after an IRQ6 (hardware
96 ; interrupt). This provides the fastest possible handling of page faults
97 ; since it jump directly here.  If this is a page fault, the number
98 ; immediately on the stack will be an error code, at offset 4 will be
99 ; the eip of the faulting instruction, at offset 8 will be the cs of the
100 ; faulting instruction.  If it is a hardware interrupt, it will not have
101 ; the error code and the eflags will be at offset 8.
102 ;----------------------------------------------------------------------------
103 cprocfar    PF_handler64k
104
105 ; Check if this is a processor exeception or a page fault
106
107         push    eax
108         mov     ax,[cs:ValidCS]     ; Use CS override to access data
109         cmp     [ss:esp+12],ax      ; Is this a page fault?
110         jne     @@ToOldHandler      ; Nope, jump to the previous handler
111
112 ; Get address of page fault and check if within our handlers range
113
114         mov     eax,cr2             ; EBX has page fault linear address
115         cmp     eax,VFLAT_START     ; Is the fault less than ours?
116         jb      @@ToOldHandler      ; Yep, go to previous handler
117         cmp     eax,VFLAT_END       ; Is the fault more than ours?
118         jae     @@ToOldHandler      ; Yep, go to previous handler
119
120 ; This is our page fault, so we need to handle it
121
122         pushad
123         push    ds
124         push    es
125         mov     ebx,eax             ; EBX := page fault address
126         and     ebx,invert 0FFFFh   ; Mask to 64k bank boundary
127         mov     ds,[cs:_PM_savedDS]; Load segment registers
128         mov     es,[cs:_PM_savedDS]
129
130 ; Map in the page table for our virtual framebuffer area for modification
131
132         mov     edi,[PDBR]          ; EDI points to page directory
133         mov     edx,ebx             ; EDX = linear address
134         shr     edx,22              ; EDX = offset to page directory
135         mov     edx,[edx*4+edi]     ; EDX = physical page table address
136         mov     eax,edx
137         mov     edx,[accessPageTable]
138         or      eax,7
139         mov     [edx],eax
140         mov     eax,cr3
141         mov     cr3,eax             ; Update page table cache
142
143 ; Mark all pages valid for the new page fault area
144
145         mov     esi,ebx             ; ESI := linear address for page
146         shr     esi,10
147         and     esi,0FFFh           ; Offset into page table
148         add     esi,[accessPageAddr]
149 ifdef   USE_NASM
150 %assign off 0
151 %rep 16
152         or      [DWORD esi+off],0000000001h ; Enable pages
153 %assign off off+4
154 %endrep
155 else
156 off = 0
157 REPT    16
158         or      [DWORD esi+off],0000000001h ; Enable pages
159 off = off+4
160 ENDM
161 endif
162
163 ; Mark all pages invalid for the previously mapped area
164
165         xchg    esi,[LastPage]      ; Save last page for next page fault
166         test    esi,esi
167         jz      @@DoneMapping       ; Dont update if first time round
168 ifdef   USE_NASM
169 %assign off 0
170 %rep 16
171         or      [DWORD esi+off],0FFFFFFFEh  ; Disable pages
172 %assign off off+4
173 %endrep
174 else
175 off = 0
176 REPT    16
177         and     [DWORD esi+off],0FFFFFFFEh  ; Disable pages
178 off = off+4
179 ENDM
180 endif
181
182 @@DoneMapping:
183         mov     eax,cr3
184         mov     cr3,eax             ; Flush the TLB
185
186 ; Now program the new SuperVGA starting bank address
187
188         mov     eax,ebx             ; EAX := page fault address
189         shr     eax,16
190         and     eax,0FFh            ; Mask to 0-255
191         call    [BankFuncPtr]       ; Call the bank switch function
192
193         pop     es
194         pop     ds
195         popad
196         pop     eax
197         add     esp,4               ; Pop the error code from stack
198         iretd                       ; Return to faulting instruction
199
200 @@ToOldHandler:
201         pop     eax
202 ifdef   USE_NASM
203         jmp far dword [cs:INT14Gate]; Chain to previous handler
204 else
205         jmp     [FWORD cs:INT14Gate]; Chain to previous handler
206 endif
207
208 cprocend
209
210 ;----------------------------------------------------------------------------
211 ; PF_handler4k  - Page fault handler for 4k banks
212 ;----------------------------------------------------------------------------
213 ; The handler below is a 32 bit ring 0 page fault handler.  It receives
214 ; control immediately after any page fault or after an IRQ6 (hardware
215 ; interrupt). This provides the fastest possible handling of page faults
216 ; since it jump directly here.  If this is a page fault, the number
217 ; immediately on the stack will be an error code, at offset 4 will be
218 ; the eip of the faulting instruction, at offset 8 will be the cs of the
219 ; faulting instruction.  If it is a hardware interrupt, it will not have
220 ; the error code and the eflags will be at offset 8.
221 ;----------------------------------------------------------------------------
222 cprocfar    PF_handler4k
223
224 ; Fill in when we have tested all the 64Kb code
225
226 ifdef   USE_NASM
227         jmp far dword [cs:INT14Gate]; Chain to previous handler
228 else
229         jmp     [FWORD cs:INT14Gate]; Chain to previous handler
230 endif
231
232 cprocend
233
234 ;----------------------------------------------------------------------------
235 ; void InstallFaultHandler(void *baseAddr,int bankSize)
236 ;----------------------------------------------------------------------------
237 ; Installes the page fault handler directly int the interrupt descriptor
238 ; table for maximum performance. This of course requires ring 0 access,
239 ; but none of this stuff will run without ring 0!
240 ;----------------------------------------------------------------------------
241 cprocstart  InstallFaultHandler
242
243         ARG     baseAddr:ULONG, bankSize:UINT
244
245         enter_c
246
247         mov     [DWORD LastPage],0  ; No pages have been mapped
248         mov     ax,cs
249         mov     [ValidCS],ax        ; Save CS value for page faults
250
251 ; Put address of our page fault handler into the IDT directly
252
253         sub     esp,6               ; Allocate space on stack
254 ifdef   USE_NASM
255         sidt    [ss:esp]            ; Store pointer to IDT
256 else
257         sidt    [FWORD ss:esp]      ; Store pointer to IDT
258 endif
259         pop     ax                  ; add esp,2
260         pop     eax                 ; Absolute address of IDT
261         add     eax,14*8            ; Point to Int #14
262
263 ; Note that Interrupt gates do not have the high and low word of the
264 ; offset in adjacent words in memory, there are 4 bytes separating them.
265
266         mov     ecx,[eax]           ; Get cs and low 16 bits of offset
267         mov     edx,[eax+6]         ; Get high 16 bits of offset in dx
268         shl     edx,16
269         mov     dx,cx               ; edx has offset
270         mov     [INT14Offset],edx   ; Save offset
271         shr     ecx,16
272         mov     [INT14Selector],cx  ; Save original cs
273         mov     [eax+2],cs          ; Install new cs
274         mov     edx,offset PF_handler64k
275         cmp     [UINT bankSize],4
276         jne     @@1
277         mov     edx,offset PF_handler4k
278 @@1:    mov     [eax],dx            ; Install low word of offset
279         shr     edx,16
280         mov     [eax+6],dx          ; Install high word of offset
281
282         leave_c
283         ret
284
285 cprocend
286
287 ;----------------------------------------------------------------------------
288 ; void RemoveFaultHandler(void)
289 ;----------------------------------------------------------------------------
290 ; Closes down the virtual framebuffer services and restores the previous
291 ; page fault handler.
292 ;----------------------------------------------------------------------------
293 cprocstart  RemoveFaultHandler
294
295         enter_c
296
297 ; Remove page fault handler from IDT
298
299         sub     esp,6               ; Allocate space on stack
300 ifdef   USE_NASM
301         sidt    [ss:esp]            ; Store pointer to IDT
302 else
303         sidt    [FWORD ss:esp]      ; Store pointer to IDT
304 endif
305
306         pop     ax                  ; add esp,2
307         pop     eax                 ; Absolute address of IDT
308         add     eax,14*8            ; Point to Int #14
309         mov     cx,[INT14Selector]
310         mov     [eax+2],cx          ; Restore original CS
311         mov     edx,[INT14Offset]
312         mov     [eax],dx            ; Install low word of offset
313         shr     edx,16
314         mov     [eax+6],dx          ; Install high word of offset
315
316         leave_c
317         ret
318
319 cprocend
320
321 ;----------------------------------------------------------------------------
322 ; void InstallBankFunc(int codeLen,void *bankFunc)
323 ;----------------------------------------------------------------------------
324 ; Installs the bank switch function by relocating it into our data segment
325 ; and making it into a callable function. We do it this way to make the
326 ; code identical to the way that the VflatD devices work under Windows.
327 ;----------------------------------------------------------------------------
328 cprocstart  InstallBankFunc
329
330         ARG     codeLen:UINT, bankFunc:DPTR
331
332         enter_c
333
334         mov     esi,[bankFunc]      ; Copy the code into buffer
335         mov     edi,offset BankFuncBuf
336         mov     ecx,[codeLen]
337     rep movsb
338         mov     [BYTE edi],0C3h     ; Terminate the function with a near ret
339
340         leave_c
341         ret
342
343 cprocend
344
345 ;----------------------------------------------------------------------------
346 ; int InitPaging(void)
347 ;----------------------------------------------------------------------------
348 ; Initializes paging system. If paging is not enabled, builds a page table
349 ; directory and page tables for physical memory
350 ;
351 ;   Exit:       0   - Successful
352 ;               -1  - Couldn't initialize paging mechanism
353 ;----------------------------------------------------------------------------
354 cprocstart  InitPaging
355
356         push    ebx
357         push    ecx
358         push    edx
359         push    esi
360         push    edi
361
362 ; Are we running under CauseWay?
363
364         mov     ax,0FFF9h
365         int     31h
366         jc      @@NotCauseway
367         cmp     ecx,"CAUS"
368         jnz     @@NotCauseway
369         cmp     edx,"EWAY"
370         jnz     @@NotCauseway
371
372         mov     [BOOL VF_haveCauseWay],1
373         mov     [CauseWayDIRLinear],esi
374         mov     [CauseWay1stLinear],edi
375
376 ; Check for DPMI
377
378         mov     ax,0ff00h
379         push    es
380         int     31h
381         pop     es
382         shr     edi,2
383         and     edi,3
384         cmp     edi,2
385         jz      @@ErrExit               ; Not supported under DPMI
386
387         mov     eax,[CauseWayDIRLinear]
388         jmp     @@CopyCR3
389
390 @@NotCauseway:
391         mov     ax,cs
392         test    ax,3                    ; Which ring are we running
393         jnz     @@ErrExit               ; Needs zero ring to access
394                                         ; page tables (CR3)
395         mov     eax,cr0                 ; Load CR0
396         test    eax,80000000h           ; Is paging enabled?
397         jz      @@ErrExit               ; No, we must have paging!
398
399         mov     eax,cr3                 ; Load directory address
400         and     eax,0FFFFF000h
401
402 @@CopyCR3:
403         mov     [PDBR],eax              ; Save it
404         mov     esi,eax
405         mov     edi,offset pageDirectory
406         mov     ecx,1024
407         cld
408         rep     movsd                   ; Copy the original page table directory
409         cmp     [DWORD accessPageAddr],0; Check if we have allocated page
410         jne     @@HaveRealMem           ; table already (we cant free it)
411
412         mov     eax,0100h               ; DPMI DOS allocate
413         mov     ebx,8192/16
414         int     31h                     ; Allocate 8192 bytes
415         and     eax,0FFFFh
416         shl     eax,4                   ; EAX points to newly allocated memory
417         add     eax,4095
418         and     eax,0FFFFF000h          ; Page align
419         mov     [accessPageAddr],eax
420
421 @@HaveRealMem:
422         mov     eax,[accessPageAddr]    ; EAX -> page table in 1st Mb
423         shr     eax,12
424         and     eax,3FFh                ; Page table offset
425         shl     eax,2
426         cmp     [BOOL VF_haveCauseWay],0
427         jz      @@NotCW0
428         mov     ebx,[CauseWay1stLinear]
429         jmp     @@Put1st
430
431 @@NotCW0:
432         mov     ebx,[PDBR]
433         mov     ebx,[ebx]
434         and     ebx,0FFFFF000h          ; Page table for 1st megabyte
435
436 @@Put1st:
437         add     eax,ebx
438         mov     [accessPageTable],eax
439         sub     eax,eax                 ; No error
440         jmp     @@Exit
441
442 @@ErrExit:
443         mov     eax,-1
444
445 @@Exit: pop     edi
446         pop     esi
447         pop     edx
448         pop     ecx
449         pop     ebx
450         ret
451
452 cprocend
453
454 ;----------------------------------------------------------------------------
455 ; void ClosePaging(void)
456 ;----------------------------------------------------------------------------
457 ; Closes the paging system
458 ;----------------------------------------------------------------------------
459 cprocstart  ClosePaging
460
461         push    eax
462         push    ecx
463         push    edx
464         push    esi
465         push    edi
466
467         mov     eax,[accessPageAddr]
468         call    AccessPage              ; Restore AccessPage mapping
469         mov     edi,[PDBR]
470         mov     esi,offset pageDirectory
471         mov     ecx,1024
472         cld
473         rep     movsd                   ; Restore the original page table directory
474
475 @@Exit: pop     edi
476         pop     esi
477         pop     edx
478         pop     ecx
479         pop     eax
480         ret
481
482 cprocend
483
484 ;----------------------------------------------------------------------------
485 ; long AccessPage(long phys)
486 ;----------------------------------------------------------------------------
487 ; Maps a known page to given physical memory
488 ;   Entry:      EAX - Physical memory
489 ;   Exit:       EAX - Linear memory address of mapped phys mem
490 ;----------------------------------------------------------------------------
491 cprocstatic     AccessPage
492
493         push    edx
494         mov     edx,[accessPageTable]
495         or      eax,7
496         mov     [edx],eax
497         mov     eax,cr3
498         mov     cr3,eax                 ; Update page table cache
499         mov     eax,[accessPageAddr]
500         pop     edx
501         ret
502
503 cprocend
504
505 ;----------------------------------------------------------------------------
506 ; long GetPhysicalAddress(long linear)
507 ;----------------------------------------------------------------------------
508 ; Returns the physical address of linear address
509 ;   Entry:      EAX - Linear address to convert
510 ;   Exit:       EAX - Physical address
511 ;----------------------------------------------------------------------------
512 cprocstatic     GetPhysicalAddress
513
514         push    ebx
515         push    edx
516         mov     edx,eax
517         shr     edx,22                  ; EDX is the directory offset
518         mov     ebx,[PDBR]
519         mov     edx,[edx*4+ebx]         ; Load page table address
520         push    eax
521         mov     eax,edx
522         call    AccessPage              ; Access the page table
523         mov     edx,eax
524         pop     eax
525         shr     eax,12
526         and     eax,03FFh               ; EAX offset into page table
527         mov     eax,[edx+eax*4]         ; Load physical address
528         and     eax,0FFFFF000h
529         pop     edx
530         pop     ebx
531         ret
532
533 cprocend
534
535 ;----------------------------------------------------------------------------
536 ; void CreatePageTable(long pageDEntry)
537 ;----------------------------------------------------------------------------
538 ; Creates a page table for specific address (4MB)
539 ;       Entry:  EAX - Page directory entry (top 10-bits of address)
540 ;----------------------------------------------------------------------------
541 cprocstatic     CreatePageTable
542
543         push    ebx
544         push    ecx
545         push    edx
546         push    edi
547         mov     ebx,eax                 ; Save address
548         mov     eax,8192
549         push    eax
550         call    VF_malloc              ; Allocate page table directory
551         add     esp,4
552         add     eax,0FFFh
553         and     eax,0FFFFF000h          ; Page align (4KB)
554         mov     edi,eax                 ; Save page table linear address
555         sub     eax,eax                 ; Fill with zero
556         mov     ecx,1024
557         cld
558         rep     stosd                   ; Clear page table
559         sub     edi,4096
560         mov     eax,edi
561         call    GetPhysicalAddress
562         mov     edx,[PDBR]
563         or      eax,7                   ; Present/write/user bit
564         mov     [edx+ebx*4],eax         ; Save physical address into page directory
565         mov     eax,cr3
566         mov     cr3,eax                 ; Update page table cache
567         pop     edi
568         pop     edx
569         pop     ecx
570         pop     ebx
571         ret
572
573 cprocend
574
575 ;----------------------------------------------------------------------------
576 ; void MapPhysical2Linear(ulong pAddr, ulong lAddr, int pages, int flags);
577 ;----------------------------------------------------------------------------
578 ; Maps physical memory into linear memory
579 ;   Entry:      pAddr   - Physical address
580 ;               lAddr   - Linear address
581 ;               pages   - Number of 4K pages to map
582 ;               flags   - Page flags
583 ;                           bit 0   =       present
584 ;                           bit 1   =       Read(0)/Write(1)
585 ;----------------------------------------------------------------------------
586 cprocstart  MapPhysical2Linear
587
588         ARG     pAddr:ULONG, lAddr:ULONG, pages:UINT, pflags:UINT
589
590         enter_c
591
592         and     [ULONG pAddr],0FFFFF000h; Page boundary
593         and     [ULONG lAddr],0FFFFF000h; Page boundary
594         mov     ecx,[pflags]
595         and     ecx,11b                 ; Just two bits
596         or      ecx,100b                ; Supervisor bit
597         mov     [pflags],ecx
598
599         mov     edx,[lAddr]
600         shr     edx,22                  ; EDX = Directory
601         mov     esi,[PDBR]
602         mov     edi,[pages]             ; EDI page count
603         mov     ebx,[lAddr]
604
605 @@CreateLoop:
606         mov     ecx,[esi+edx*4]         ; Load page table address
607         test    ecx,1                   ; Is it present?
608         jnz     @@TableOK
609         mov     eax,edx
610         call    CreatePageTable         ; Create a page table
611 @@TableOK:
612         mov     eax,ebx
613         shr     eax,12
614         and     eax,3FFh
615         sub     eax,1024
616         neg     eax                     ; EAX = page count in this table
617         inc     edx                     ; Next table
618         mov     ebx,0                   ; Next time we'll map 1K pages
619         sub     edi,eax                 ; Subtract mapped pages from page count
620         jns     @@CreateLoop            ; Create more tables if necessary
621
622         mov     ecx,[pages]             ; ECX = Page count
623         mov     esi,[lAddr]
624         shr     esi,12                  ; Offset part isn't needed
625         mov     edi,[pAddr]
626 @@MappingLoop:
627         mov     eax,esi
628         shr     eax,10                  ; EAX = offset to page directory
629         mov     ebx,[PDBR]
630         mov     eax,[eax*4+ebx]         ; EAX = page table address
631         call    AccessPage
632         mov     ebx,esi
633         and     ebx,3FFh                ; EBX = offset to page table
634         mov     edx,edi
635         add     edi,4096                ; Next physical address
636         inc     esi                     ; Next linear page
637         or      edx,[pflags]            ; Update flags...
638         mov     [eax+ebx*4],edx         ; Store page table entry
639         loop    @@MappingLoop
640         mov     eax,cr3
641         mov     cr3,eax                 ; Update page table cache
642
643         leave_c
644         ret
645
646 cprocend
647
648 endcodeseg  _vflat
649
650 endif
651
652         END                     ; End of module