home *** CD-ROM | disk | FTP | other *** search
- ;;
- ;; This is file GRPROT.ASM
- ;;
- ;; Copyright (C) 1993 DJ Delorie, 24 Kirsten Ave, Rochester NH 03867-2954
- ;; Copyright (C) 1993 Csaba Biegl, csaba@vuse.vanderbilt.edu
- ;; Copyright (C) 1993 Grzegorz Mazur, gbm@ii.pw.edu.pl
- ;;
- ;; This file is distributed under the terms listed in the document
- ;; "copying.dj", available from DJ Delorie at the address above.
- ;; A copy of "copying.dj" should accompany this file; if not, a copy
- ;; should be available from where this file was obtained. This file
- ;; may not be distributed without a verbatim copy of "copying.dj".
- ;;
- ;; This file is distributed WITHOUT ANY WARRANTY; without even the implied
- ;; warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- ;;
-
- ; History:270,22
- title grprot
- .386p
-
- include segdefs.inc
- include tss.inc
- include gdt.inc
- include idt.inc
-
- ;------------------------------------------------------------------------
- ;
- ; Memory Map (relative to 0xe0000000) :
- ; 00000000 - 000fffff == read/write area
- ; 00100000 - 001fffff == read only area
- ; 00200000 - 002fffff == write only area
- ; 01000000 - 01ffffff == 16MB read/write area
- ; 02000000 - 02ffffff == 16MB read only area
- ; 03000000 - 03ffffff == 16MB write only area
- ;
- ; If your board can support separate read & write mappings,
- ; like the TSENG chips, then either one of two cases applies:
- ; 1. The read and write mappings are the same, and the rw, r,
- ; and w areas all have one present bank.
- ; 2. The read and write mappings are different, and only the
- ; r and w areas have a mapped bank. Accesses to the rw area
- ; cause a page fault and the board goes back into case #1.
- ;
- ; If your board can't support separate read & write mappings,
- ; always map the rw, r, and w areas to the same page (case #1 above)
- ;
- ; It is up to the programmer to ensure that the program doesn't
- ; read from the write only area, or write to the read only area.
- ;
- ; This method is used because you can't use the string move instructions
- ; across pages. The "movsx" instruction causes *two* memory references,
- ; potentially to different banks. The first causes one bank to be
- ; enabled, and the instruction is restarted. The second access causes
- ; the second bank to be enabled, and the instruction is *RESTARTED*.
- ; This means it will attempt the *first* access again, causing it to be
- ; enabled, ad infinitum.
- ;
- ; Thus, bcopy() and memcpy() shouldn't *ever* access the rw area!
- ;
- ;------------------------------------------------------------------------
-
- extrn _graphics_pt1_lin:dword ; page table #1
- extrn _graphics_pt2_lin:dword ; page table #2
- extrn _graphics_pt1_loc:word ; current location of page table #1
- extrn _graphics_pt2_loc:word ; current location of page table #2
- extrn _graphics_pd_lin:dword ; ptr to graphics section of PD
- extrn _graphics_pd_seg_lin:dword ; ptr to graphics section of Pseg Dir
-
- extrn _gr_paging_func:dword ; the paging function
-
- extrn _gr_r_w_page_size:dword ; read or write only page size in 4K units
- extrn _gr_sgl_page_size:dword ; R/W page size in 4K units
- extrn _gr_r_w_page_shift:byte ; log2 of read or write only page size/4K
- extrn _gr_sgl_page_shift:byte ; log2 of R/W page size/4K
- extrn _gr_rw_page_offset:byte ; diff between pages in R/W mode (ATI!)
-
- extrn _gr_rw_table_lin:dword ; prepared R/W page table section
- extrn _gr_ro_table_lin:dword ; prepared read only page table section
- extrn _gr_wo_table_lin:dword ; prepared write only page table section
-
- ;;
- ;; current and previous paging mode codes:
- ;;
- BIGPAGE equ 2
- SINGLE equ 4
- WRFAULT equ 8
-
- mode_r_w equ 0 ; split 1M pages
- mode_r_w_big equ mode_r_w + BIGPAGE ; split 16M pages
- mode_sgl equ SINGLE ; single 1M R/W page
- mode_sgl_big equ mode_sgl + BIGPAGE ; single 16M R/W page
- mode_rr_w equ mode_r_w ; split 1M: read fault
- mode_rr_w_big equ mode_r_w_big ; split 16M: read fault
- mode_r_ww equ mode_r_w + WRFAULT ; split 1M: write fault (current only)
- mode_r_ww_big equ mode_r_w_big + WRFAULT ; split 16M: write fault (current only)
-
- start_data16
-
- cur_p dw 0 ; current mapped r/w or read only page
- cur_w dw 0 ; current mapped write only page
- mode dw mode_sgl ; current paging mode
- VGA_w db 0 ; current VGA write page
- VGA_r db 0 ; current VGA read page
-
- end_data16
-
- ;------------------------------------------------------------------------
- ;
- ; the graphics page fault routine
- ;
- ;------------------------------------------------------------------------
- start_code16
-
- extrn _page_fault:near
- public graphics_fault
-
- graphics_fault:
- cli
- cld
- mov ax,g_core
- mov es,ax
- mov ebx,cr2
-
- shr ebx,20 ; bx: fault loc/1Meg
- mov dx,bx
- shr dx,2 ; dx: fault loc/4Meg
- and bx,03h ; mask multiple of 1MB bits (0..3)
- and dx,0ch ; mask multiple of 16MB bits (0..3)
- or bx,dx
-
- ; shr ebx,10
- ; shr bh,2
- ; shr bx,10
-
- mov bl,cs:mode_table[bx]
- mov bp,bx ; bp: new paging mode
- lea si,_graphics_pt1_loc ; check page table position in pg dir
- cmp bp,mode_r_ww_big
- jne check_pgdir
- lea si,_graphics_pt2_loc ; here we need the second page table
- check_pgdir:
- mov ax,[si]
- mov ebx,cr2
- shr ebx,22
- and bx,(03ffffffh SHR 22)
- cmp ax,bx ; ax: old, bx: new
- je pgdir_done
- and eax,0000ffffh
- xor edx,edx
- mov edi,_graphics_pd_lin
- mov ecx,es:[edi+eax*4] ; move page table
- mov es:[edi+ebx*4],ecx
- mov es:[esi+eax*4],edx ; zero old entry
- mov edi,_graphics_pd_seg_lin
- mov cl,es:[edi+eax] ; move page table segment
- mov es:[edi+ebx],cl
- mov es:[edi+eax],dl ; zero old entry
- mov [si],bx
- pgdir_done:
- mov edx,cr2
- shr edx,12
- and dx,(03ffffffh SHR 12) ; dx: page index where fault occurred
- mov bx,dx ; bx: VGA page in 4kByte units
- and bx,(00ffffffh SHR 12) ; mask out 16MB region indicators
- jmp cs:pginv_table[bp]
-
- pginv_table label word ; dispatch to invalidate old page table(s)
- dw offset invalidate_rr_w
- dw offset invalidate_rr_w_big
- dw offset invalidate_sgl
- dw offset invalidate_sgl_big
- dw offset invalidate_r_ww
- dw offset invalidate_r_ww_big
-
- mode_table label byte ; table of paging modes depending on addr
- db mode_sgl
- db mode_rr_w
- db mode_r_ww
- db -1 ; should never need this!!!
- db mode_sgl_big
- db mode_sgl_big
- db mode_sgl_big
- db mode_sgl_big
- db mode_rr_w_big
- db mode_rr_w_big
- db mode_rr_w_big
- db mode_rr_w_big
- db mode_r_ww_big
- db mode_r_ww_big
- db mode_r_ww_big
- db mode_r_ww_big
-
- invalidate_rr_w: ; split page: read fault
- and bx,(000fffffh SHR 12) ; mask out 1MB region indicator
- invalidate_rr_w_big:
- mov cl,_gr_r_w_page_shift
- shr dx,cl ; truncate page to VGA limits
- shl dx,cl
- and bx,(00ffffffh SHR 12) ; mask out 16MB region indicator
- shr bx,cl ; figure out VGA page
- mov VGA_r,bl
- mov edi,_graphics_pt1_lin ; edi: zero in this page table
- mov ecx,edi ; ecx: copy to this page table
- mov esi,_gr_ro_table_lin ; esi: copy from this prepared table
- mov ebx,_gr_r_w_page_size ; ebx: copy this many entries
- mov ax,cur_p ; ax: zero from this position
- mov cur_p,dx ; dx: copy here, also updated mapping index
- jmp invalidate_ptable
-
- invalidate_r_ww: ; split page: write fault
- and bx,(000fffffh SHR 12) ; mask out 1MB region indicator
- invalidate_r_ww_big:
- mov cl,_gr_r_w_page_shift
- shr dx,cl ; truncate page to VGA limits
- shl dx,cl
- and bx,(00ffffffh SHR 12) ; mask out 16MB region indicator
- shr bx,cl ; figure out VGA page
- mov VGA_w,bl
- mov ecx,_graphics_pt1_lin ; ecx: copy to this page table
- mov esi,_gr_wo_table_lin ; esi: copy from this prepared table
- mov ebx,_gr_r_w_page_size ; ebx: copy this many entries
- mov ax,cur_w ; ax: zero from this position
- mov cur_w,dx ; dx: copy here, also updated mapping index
- test bp,BIGPAGE ; is ptable1 correct?
- je invalidate_r_ww_dispatch
- mov ecx,_graphics_pt2_lin ; ecx: copy to this page table
- invalidate_r_ww_dispatch:
- mov di,mode
- jmp cs:inv_r_ww_oldmd[di] ; figure out how to invalidate based on old mode
- inv_r_ww_oldmd label word
- dw inv_r_ww_old_r_w
- dw inv_r_ww_old_r_w_big
- dw inv_r_ww_old_sgl
- dw inv_r_ww_old_sgl_big
- inv_r_ww_old_r_w:
- mov edi,_graphics_pt1_lin ; edi: zero in this page table
- jmp invalidate_ptable
- inv_r_ww_old_r_w_big:
- mov edi,_graphics_pt2_lin ; edi: zero in this page table
- jmp invalidate_ptable
- inv_r_ww_old_sgl:
- inv_r_ww_old_sgl_big:
- mov edi,_graphics_pt1_lin ; edi: zero in this page table
- mov ax,cur_p ; ax: zero from this position
- jmp invalidate_ptable
-
- invalidate_sgl:
- invalidate_sgl_big:
- test mode,SINGLE
- jne invalidate_one_table_only
- mov edi,_graphics_pt1_lin
- test mode,BIGPAGE
- je invalidate_wr_ptable
- mov edi,_graphics_pt2_lin
- invalidate_wr_ptable:
- mov cx,cur_w
- and ecx,1023
- lea edi,[edi+ecx*4]
- mov ecx,_gr_r_w_page_size
- xor eax,eax
- rep
- db 67h
- stosd
- invalidate_one_table_only:
- mov cl,_gr_sgl_page_shift
- shr dx,cl ; truncate page to VGA limits
- shl dx,cl
- shr bx,cl ; figure out VGA pages
- mov cl,_gr_rw_page_offset ; ATI style paging hack
- shl bl,cl
- mov VGA_w,bl
- add bl,cl
- mov VGA_r,bl
- mov edi,_graphics_pt1_lin ; edi: zero in this page table
- mov ecx,edi ; ecx: copy to this page table
- mov esi,_gr_rw_table_lin ; esi: copy from this prepared table
- mov ebx,_gr_sgl_page_size ; ebx: copy this many entries
- mov ax,cur_p ; ax: zero from this position
- mov cur_p,dx ; dx: copy here, also updated mapping index
-
- invalidate_ptable:
- and eax,1023
- lea edi,[edi+eax*4] ; edi: zero page table here
- and edx,1023
- lea edx,[ecx+edx*4] ; edx: copy into page table here
- mov ecx,_gr_sgl_page_size ; entries to clear at edi
- test bp,SINGLE ; correct?
- jne clear_ptable
- mov ecx,_gr_r_w_page_size ; now it is!
- clear_ptable:
- xor eax,eax
- rep
- db 67h
- stosd
- mov edi,edx ; copy into page table here
- mov ecx,ebx ; this many entries
- mov dx,ds
- mov ax,g_core
- mov ds,ax
- rep
- db 67h
- movsd
- mov ds,dx
- and bp,(SINGLE + BIGPAGE) ; update mode
- mov mode,bp
-
- mov ax,word ptr VGA_w
- call dword ptr [_gr_paging_func] ; call paging func
-
- mov eax,cr3
- mov cr3,eax
-
- pop eax
- iretd ; back to running program
- jmp _page_fault
-
- end_code16
-
- ;------------------------------------------------------------------------
- ; Real mode paging assist code.
- ; The idea is that we have to call the driver's paging function in real
- ; mode. GRAPHICS.C's 'graphics_assist' function provides this service
- ; by intercepting the int 0x10, ah=0xff calls. Unfortunately we cannot
- ; issue this call from the paging task. Instead the paging routine only
- ; changes the arena task's eip to point to a routine which invokes
- ; int 10 first thing when the arena task resumes. A temporary buffer
- ; is used to save the arena task's eax and ebx. The same buffer
- ; holds the VGA page values. The virtual address of this buffer is passed
- ; to the arena task in the eax register. This solution was necessary because
- ; it is not certain what would happen if we got a second page fault here
- ; (for which there is a slight chance if we try to use the arena's stack).
- ; For safety the buffer also contains a busy flag which is cleared by
- ; the arena routine after completion. The arena task's state is not changed
- ; if this flag is set. The effect of this is that the VGA is not reprogrammed
- ; but a garbled screen is still much better than a crashed program! Anyway,
- ; this should not happen unless some smartass tries to do multitasking
- ; time-sliced graphics (did anyone say that the graphics libs were
- ; reentrant?)
- ;------------------------------------------------------------------------
-
- extrn _real_paging_buffer_lin:dword ; linear address the way I see it
- extrn _real_paging_buffer_virt:dword ; address the way the arena sees it
- extrn _real_paging_func_virt:dword ; arena address of the 'int 0x10' func
- extrn _a_tss:tss_s
-
- start_code16
-
- public _real_paging_routine
- _real_paging_routine proc far
- mov esi,_real_paging_buffer_lin
- cmp byte ptr es:[esi],0 ; busy ?
- jne paging_busy ; note: this runs with IT-s disabled
- mov byte ptr es:[esi],1 ; so we can do this non-atomic stuff
- mov ebx,_a_tss.tss_eax
- mov es:[esi+4],ebx ; save arena eax
- mov ebx,_a_tss.tss_ebx
- mov es:[esi+8],ebx ; save arena ebx
- mov es:[esi+12],eax ; put VGA page indices in buffer
- mov ebx,_a_tss.tss_eip
- mov _a_tss.tss_ebx,ebx ; pass arena's old eip in ebx to it
- mov ebx,_real_paging_func_virt
- mov _a_tss.tss_eip,ebx ; change arena eip
- mov ebx,_real_paging_buffer_virt
- mov _a_tss.tss_eax,ebx ; pass buffer address in eax
- paging_busy:
- ret
- _real_paging_routine endp
-
- end_code16
-
- ;------------------------------------------------------------------------
- ; The real mode paging hook in the arena task.
- ;------------------------------------------------------------------------
- _TEXT32 segment dword public 'code' use32
- assume cs:_TEXT32,ds:nothing,ss:nothing
-
- public _arena_real_paging_func
- _arena_real_paging_func:
- push ebx ; save return address
- pushf ; save flags
- mov ebx,[eax+4]
- push ebx ; stack old eax
- mov ebx,[eax+8]
- push ebx ; stack old ebx
- mov ebx,[eax+12] ; VGA page indices
- push eax
- mov ax,0fffdh ; 'graphics_assist' fnc code
- int 10h
- pop eax
- mov byte ptr [eax],0 ; clear busy flag
- pop ebx
- pop eax
- popf
- ret
-
- _TEXT32 ends
-
- ;------------------------------------------------------------------------
-
- end