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