pcs/extsmmu.asm

607 lines
17 KiB
NASM
Raw Normal View History

2023-05-20 05:57:05 -04:00
name SMMU
title Scheme Memory Management Utilities
page 62,132
; =====> SMMU.ASM
;****************************************************************
;* TIPC Scheme '84 Memory Management Utilities *
;* *
;* (C) Copyright 1985, 1987 by Texas Instruments Incorporated. *
;* All rights reserved. *
;* *
;* Author: Herman Schuurman *
;* Date written: 26 August 1985 *
;* Last change: 17 September 1985 *
;* History: *
;* rb 4/ 5/87 "getbase" returns in carry flag a page's *
;* swap state *
;****************************************************************
.286c ;; Utilize the expanded 80286 instruction set
include pcmake.equ
include schemed.equ
include schemed.ref
include schemed.mac
DOS equ 021h
ExtAlloc equ 99 ;; # extended mem pages to allocate initially
;; (99 effectively removes barrier)
DGROUP group data
PGROUP group prog
data segment word public 'DATA'
assume ds:DGROUP
extrn page0:byte, page4:byte, page5:byte, page6:byte
extrn page7:byte, page8:byte
extrn _top:word, _paras:word,first_pa:word,first_dos:word
;; Age table
agetable label word
dw NUMPAGES dup (0)
AllocPag dw 0 ;; Allocated number of pages
;;
;; The following EQUates give the special bits within the page table,
;; mainly used for the CLOCK algorithm. Note that these equates are
;; also defined in SBIGEXT.C if modified.
SWAPPED equ 00000001b ;; Page is currently in extended memory
FIXED equ 10000000b ;; Fixed in memory (long pages)
PageBuf dw SWAPPED ;; Current available swap page (default 0)
public VMCycle
VMCycle dw 0 ;; Current VM cycle (modulo 65536)
;; public FAULTS
;;FAULTS dw 0 ;; Number of page faults
public GC_ING
GC_ING dw 0 ;; Indicate whether garbage collecting
m_lck_er db "[VM FATAL ERROR] Memory lock error - no page to swap",0Ah,0
m_pag_er db "[VM FATAL ERROR] Memory paging error number "
p_errnum db 30h
db 0Ah,0
;; Extended memory support structures....
DESC struc ;; Data segment descriptor
DESCLimit dw MIN_PAGESIZE ;; Segment limit (length)
DESCBaseL db 0 ;; Physical address - bits 7..0
DESCBaseM dw 0 ;; Physical address - bits 23..8
db 0 ;; Access rights byte
dw 0 ;; Intel reserved....
DESC ends
;;======================================================================
;;
;; The GDT passed to INT 15h function 87h, is organized as follows :
;;
;; .-----------.
;; V |
;; [ES:SI] --> +00 .---------------. |
;; | Dummy | |
;; +08 |---------------| |
;; | GDT Loc |---'
;; +10 |---------------|
;; | Source GDT |
;; +18 |---------------|
;; | Target GDT |
;; +20 |---------------|
;; | BIOS code seg |
;; +28 |---------------|
;; | Stack segment |
;; `---------------'
;;
;;======================================================================
GDT label byte ;; Begin of global descriptor table
DESC <> ;; Dummy descriptor
DESC <> ;; GDT descriptor
Source DESC <,,,93h,> ;; Source area descriptor
Target DESC <,,,93h,> ;; Target area descriptor
DESC <> ;; BIOS code segment descriptor
DESC <> ;; Stack segment descriptor
data ends
prog segment byte public 'PROG'
assume cs:PGROUP
public _MMU,_%MMU
;; The following are here so link edit won't find urevolved refs
public _%MMU0,_%MMU1,_MMUCB
public getbase
public InitMem
extrn print_an:near ;; print_and_exit (truncated to 8 chars)
;;======================================================================
;;
;; _MMU - Get page indicated on stack into real memory,
;; and return the paragraph address of it on the stack...
;;
;;======================================================================
Lcl_DS_Save dw data ;; Saved Data Segment
_%MMU proc far ;; Entry from PROGX segment
_%MMU0:
_%MMU1:
push AX
call _MMU
pop AX
ret
_%MMU endp
_MMU proc near ;; Normal Entry from PROG segment
_MMUCB:
push BP ;; Make stack accessable
mov BP,SP
push DS ;; Save Caller's DS
mov DS,CS:Lcl_DS_Save ;; and make our's available
push AX
push BX
mov BX,word ptr [bp+4] ;; Get pagetabl offset
mov AX,word ptr pagetabl+[BX] ;; Get (new) table indicator
cmp BX,PreAlloc*2 ;; If one of dedicated pages
jb M_RetPage ;; then jump
test byte ptr [pagetabl+BX],SWAPPED ;; If in extended memory
jne M_Swap ;; then go swap it in
;; Update age and return para address
M_Ret:
inc VMCycle ;; Time stamp
jnz M_Ret01 ;; On overflow
call PgSweep ;; Go sweep entire pagetabl
M_Ret01:
mov AX,VMCycle ;; Get time stamp
mov word ptr agetable+[BX],AX ;; Place in ageing table
mov AX,word ptr pagetabl+[BX] ;; Get paragraph address
xor AL,AL
M_RetPage:
mov word ptr [BP+4],AX ;; Set return value
pop BX
pop AX
pop DS
pop BP
ret
;; Retrieve page from extended memory
M_Swap:
pusha ;; Save all registers
push ES ;; including ES
push AX ;; Save page number on stack
push BX ;; Save the page table entry
call FndPage ;; Find a page for swapping
pop DI ;; Retrieve final destination
mov AX,PageBuf ;; Set swapped page address
xchg pagetabl+[BX],AX ;; Get the current page contents
xor AL,AL ;; Remove attribute bits
mov pagetabl+[DI],AX
mov BX,PageBuf ;; Get the page buffer address
shr BX,2 ;; Adjust the page base address
add BH,10h ;; and raise above 1MByte
shr AX,4 ;; Create a correct address
push AX ;; Save source as next destination
call MovePage ;; Swap old page out
pop BX ;; Set next destination
pop AX ;; and old source
mov PageBuf,AX ;; Set new swap page
shr AX,2
add AH,10h
call MovePage ;; Swap new page in
pop ES ;; Restore all registers
popa ;; including ES
;; inc FAULTS ;; update page fault count
jmp M_Ret
_MMU endp
;;======================================================================
;;
;; PgSweep - page table clocked sweep routine.
;; This routine cleans up the current page table after a full
;; reference cycle (253 counts).
;;
;;======================================================================
public PgSweep
PgSweep proc near
push AX
push BX
push CX
mov BX,offset agetable[PreAlloc*2] ;; Don't bother with the
mov CX,AllocPag ;; dedicated pages in the table
xor AX,AX ;; Clear AX register
PgSwp$0:
mov AL,byte ptr [BX+1] ;; Get the current high byte
mov word ptr [BX],AX
add BX,2
loop PgSwp$0 ;; Continue with next sweep
mov VMCycle,100h ;; Set next cycle
pop CX
pop BX
pop AX
ret
PgSweep endp
;;======================================================================
;;
;; FndPage - Find a swappable page in the page table.
;; This routine scans the page table (non-dedicated pages only),
;; for swappable pages. The least recently used page NOT USED
;; IN THE CURRENT VM INSTRUCTION is selected...
;;
;; As an added bonus, the current code page can not be swapped
;; either.....
;;
;;======================================================================
FndPage proc near
mov BX,cb_pag ;; Get entry into current code page
cmp BX,PreAlloc*2 ;; Check against permanent pages
jb FndPag$1 ;; Don't worry...it'll stay around
cmp pagetabl+[BX],FIXED ;; Check for fixed page
jbe FndPag$1 ;; which will stay too
mov AX,VMCycle ;; Set to current cycle
mov agetable+[BX],AX ;; Try to keep page in memory
FndPag$1:
mov BX,PreAlloc*2 ;; Don't bother with the
mov CX,AllocPag ;; dedicated pages in the table
xor DX,DX ;; Set initial distance
FndPag$2:
test byte ptr [BX+pagetabl],FIXED+SWAPPED
jne FndPag$3 ;; Fixed,Swapped,Noswap pages are exempt
mov AX,VMCycle ;; Check against current cycle
sub AX,agetable+[BX]
cmp DX,AX
jae FndPag$3 ;; Already found a better page
mov SI,BX ;; Save the page address
mov DX,AX ;; and its value
FndPag$3:
add BX,2
loop FndPag$2 ;; Continue with next sweep
;; Completed the sweep..the most desirable page should
;; be in SI now, unless DX is still 0....
cmp DX,0 ;; See if we found a page
je FndPag$4 ;; No...error
mov BX,SI ;; Return its number
ret
public FndPag$4
FndPag$4:
lea BX,m_lck_er ;; Indicate a lock error
FatalError:
push BX ;; Save the error message
mov AX,DS
mov ES,AX ;; Make sure ES is Ok...
C_call print_an ;; Print the message and quit
FndPage endp
;;======================================================================
;;
;; Get page base address without forcing a page fault.
;; For debugging purposes only (SDUMP.C)....
;;
;; On exit, set carry if page is swapped out, else clear carry (used by XLI)
;;
;;======================================================================
getbase proc near
push BP
mov BP,SP
mov BX,word ptr [BP+4]
mov AX,word ptr [BX+pagetabl] ;; Get table indicator
test AX,SWAPPED ; is page swapped out?
jz getb_10 ; no, jump
stc ; page is swapped out, set carry
jmp short getb_20
getb_10: clc ; page is in memory, clear carry
getb_20: pop BP
ret
getbase endp
;;======================================================================
;;
;; Swap page to extended memory
;; Used in FIND_BIG_BLOCK in SBIGMEM.C
;;
;;======================================================================
public move_pag
move_pag proc near
push BP
mov BP,SP
pusha ;; Save all registers
push ES ;; including ES
mov DI,[BP+6] ;; Extended memory page to swap
mov AX,word ptr pagetabl+[DI] ;; AX <= Extended memory address
mov BX,[BP+4] ;; Real memory page to swap
xchg pagetabl+[BX],AX ;; Update its pagetabl entry
xor AL,AL ;; AX <= para address of page to swap
push DI
push AX
mov BX,word ptr [BX+pagetabl] ;; Extended page address (destination)
shr BX,2 ;; Adjust page base address
add BH,10h ;; and raise above 1mb address
shr AX,4 ;; Real page address (source)
call MovePage ;; Move it
pop AX ;; Reload paragraph address
or AL,FIXED ;; Fixed attribute
pop DI ;; Reload page number
mov word ptr pagetabl+[DI],AX ;; Update pagetabl entry
pop ES ;; Restore all regs
popa ;; including ES
pop BP ;; restore base ptr
ret
move_pag endp
subttl Extended memory support
page
;;======================================================================
;;
;; Extended memory I/O routine
;;
;; Source address is in AX, destination in BX.
;; The high byte of each register contains the upper 8 bits of
;; the real address (bits 16..23). The low byte contains the
;; next 8 bits of the real address (bits 8..15)...
;;
;;======================================================================
MovePage proc near
mov SI,SS
mov CX,SP ; Save the original stack in SI:CX
cli
mov DX,CS
mov SS,DX
mov SP,offset PGROUP:ExtMemStack
sti
push SI
push CX ; Save old stack info
mov Source.DESCBaseM,AX
mov Target.DESCBaseM,BX
mov CX,MIN_PAGESIZE/2 ;; Reduce pagesize to word count
push DS
pop ES
mov SI,offset DGROUP:GDT
mov AH,87h ; Perform a block move
int 15h
; kludge to fix hanging keyboard
mov AL,0AEh ; ensure keyboard enabled
out 64h,AL ; output to 8042 controller
pop CX
pop BX
cli
mov ss,BX ; Restore the original stack
mov sp,CX
sti
jz MovRet ; If successful, return
or AH,AH ; Return status non-zero?
jnz MovePage$1 ; Yes...error
MovRet:
ret
;; Error detected durin paging ....as fatal as can be....
MovePage$1:
or p_errnum,AH ; Set error indicator
lea BX,m_pag_er ; Load up Error message
jmp FatalError ; Abort
MovePage endp
;;======================================================================
;;
;; InitMem()
;; Initialize all the memory tables correctly. Return the
;; total number of pages (excluding the dedicated ones) we've
;; been able to allocate.
;;
;;======================================================================
InitMem proc near
mov BX,DS
mov CS:Lcl_DS_Save,BX ;; Save DS for manager above
mov ES,BX ;; Ensure ES = DS
;; Convert offset within pagetabl[0] into paragraph address
mov DI,offset pagetabl
mov AX,word ptr [DI]
mov CX,4
shr AX,CL
add AX,BX
mov word ptr [DI],AX
;; Same for pagetabl[4] through pagetabl[8]
mov DX,5
mov DI,offset pagetabl[8]
EmmP$0:
mov AX,word ptr [DI]
shr AX,CL
add AX,BX
mov word ptr [DI],AX
add DI,2
dec DX
jnz EmmP$0
;; Compute first page paragraph address
;; (In the process, allocate all the memory that DOS will give us.)
mov BX,0FFFFh ;; first ask for too much
mov AH,048h
int DOS ;; DOS gets an error, but tells us
;; in BX how much we CAN get
mov AH,048h
int DOS ;; reissue allocation request
mov first_dos,AX ;; save address for returning it to DOS
add AX,(MIN_PAGESIZE shr 4) - 1 ;; Move to page boundary
and AX,not ((MIN_PAGESIZE shr 4) - 1)
mov first_pa,AX ;; first page paragraph address
;; Initialize page management table with pages available in real memory
mov DX,nextpage
mov freepage,DX ;; freepage = nextpage
mov DI,_paras ;; Get maximum number of paragraphs
sub DI,(MIN_PAGESIZE shr 4) ;; Get address of last paragraph
xor CX,CX ;; Keep number of pages in CX
InitM$1:
cmp DI,AX ;; Did we reach it
jb InitM$2 ;; Yes...no more
cmp DX,NUMPAGES ;; See if we have filled the table
jae InitM$2
mov BX,DX
shl BX,1
mov word ptr [BX+pagetabl],AX
and word ptr [BX+attrib],not NOMEMORY
inc DX
mov word ptr [BX+pagelink],DX
mov word ptr [BX+nextcell],0
inc CX ;; page_count++
add AX,(MIN_PAGESIZE shr 4)
jmp InitM$1
;;
;; At this time, DX <= next avail page number, CX <= current page count
;;
;; Now Lets see if this is a 286 machine
;;
InitM$2:
mov nextpage,DX ;; Save next available page
xor AX,AX
mov BX,PC_MAKE ;; Get pc type
cmp BX,1 ;; Is it TIPC?
jne InitM$20 ;; No, go check for 286/386
push DS ;; Yes,lets check for a Bus Pro
mov DS,AX ;; DS <= 0 for addressing low mem
mov BX,DS:word ptr [01A2h] ;; Checkout vector 68 bytes 2 & 3
pop DS
add BL,BH
cmp BL,0F0h ;; If AL==F0 then TIPC=Business Pro
je InitM$21
jne InitM$Ret
InitM$20:
cmp BX,IBMAT ;; Is it IBM AT?
;; (includes XT/286, PS/2-50,-60)
je InitM$21 ;; yes, jump
cmp BX,IBM80 ;; Is it IBM PS/2 Model 80?
jne InitM$Ret ;; no, jump
;; Fill out rest of page table with extended memory pages. Only allocate
;; the first 512kb of extended memory; the rest is allocated but marked
;; marked as unallocated in the page tables (ie, ATTRIB and PAGELINK). This
;; will force the memory allocation to work (at least initially) in real
;; memory and the first 512k of extended memory until an "out of memory".
;; At that time, NEXTPAGE will be updated, and some more pages in extended
;; memory will then be marked as allocated (ie, ATTRIB and PAGELINK). This
;; scenario will be repeated until all of extended memory is actually used.
;; The upper limit will be help in LASTPAGE. Also see out_of_memory in
;; SMEMORY.C
;;
;; This should help performance for those applications which generate a
;; lot of garbage, but don't have to use the full extent of the extended
;; memory.
InitM$21:
push CX ;; Save current count
mov AH,88h ;; Get number of contiguous 1k
int 15h ;; blocks starting at 1MByte
add ax,((MIN_PAGESIZE shr 10) - 1)
and ax,not ((MIN_PAGESIZE shr 10) - 1)
xor DX,DX
mov CX,(MIN_PAGESIZE shr 10);; Number 1K blocks per page
idiv CX ;; Reduce to # of pages
mov DX,nextpage ;; Retrieve next available page number
mov CX,0101h ;; Count the extended pages
xor DI,DI
InitM$3:
dec AX ;; Check for last extended memory page
jle InitM$4 ;; Yes...no more
cmp DX,NUMPAGES ;; See if we have filled the table
jae InitM$4
mov BX,DX ;; DX = page number
shl BX,1 ;; BX = page table offset
inc DX ;; DX = next page number
mov word ptr [BX+pagetabl],CX ;; Page's address
mov word ptr [BX+nextcell],0 ;; Nextcell in page = 0
cmp CH,ExtAlloc ;; 512kb allocated?
jb InitM$33 ;; below, mark as allocated
ja InitM$35 ;; above, skip allocation
mov DI,DX ;; equal, EXT MEM LIMIT
InitM$33:
and word ptr [BX+attrib],not NOMEMORY
mov word ptr [BX+pagelink],DX ;; No, update pagelink info
InitM$35:
inc CH ;; Next extended memory page
jmp InitM$3 ;; Go allocate next page
;; At this time, DX <= last page number, CH <= # extended memory pages
InitM$4:
mov lastpage,DX ; last page number
mov nextpage,DX ; default nextpage to lastpage
or DI,DI ; Did we get our extended mem limit?
jz InitM$45 ; no, lastpage=nextpage, jump
mov nextpage,DI ; yes, lets use that limit
InitM$45:
xor AH,AH
mov AL,CH ; Get extended memory count
dec AX ; Don't count the swapping page
pop CX ; Retrieve real memory count
InitM$Ret:
add AX,CX ; Total Page count
mov AllocPag,AX ; Save allocated pages for later
ret
InitMem endp
;;======================================================================
;;
;; Temporary stack during extended memory operations...
;;
;;======================================================================
db 10 dup ("ExtStack")
ExtMemStack label word ;; Extended memory support stack
prog ends
end