268 lines
7.8 KiB
NASM
268 lines
7.8 KiB
NASM
name PROSMMU
|
||
title Scheme Memory Management Utilities for Protected Mode
|
||
page 62,132
|
||
; =====> PROSMMU.ASM
|
||
;****************************************************************
|
||
;* TIPC Scheme '84 Memory Management Utilities *
|
||
;* *
|
||
;* (C) Copyright 1985 by Texas Instruments Incorporated. *
|
||
;* All rights reserved. *
|
||
;* *
|
||
;* Author: Terry Caudill *
|
||
;* Date written: 17 Feb 1987 *
|
||
;****************************************************************
|
||
include schemed.equ
|
||
include schemed.ref
|
||
include schemed.mac
|
||
|
||
DOS equ 021h
|
||
|
||
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
|
||
|
||
public scheme_heap,gc_ing
|
||
scheme_heap dw 0 ;selector for entire scheme heapspace
|
||
gc_ing dw 0 ;denotes when gc is taking place
|
||
|
||
sub_segerr db "Error allocating data segment",0Ah,0
|
||
alloc_err db "Unable to allocate memory for scheme heap",0Ah,0
|
||
|
||
data ends
|
||
|
||
|
||
prog segment byte public 'PROG'
|
||
assume cs:PGROUP
|
||
|
||
;;======================================================================
|
||
;;
|
||
;; Get page base address of page
|
||
;;
|
||
;;======================================================================
|
||
|
||
public getbase
|
||
getbase proc near
|
||
push BP
|
||
mov BP,SP
|
||
mov BX,word ptr [BP+4]
|
||
mov AX,word ptr [BX+pagetabl] ;; Get table indicator
|
||
pop BP
|
||
ret
|
||
|
||
getbase endp
|
||
|
||
;;======================================================================
|
||
;;
|
||
;; InitMem()
|
||
;; Compute the best page size, but not smaller than MIN_PAGESIZE
|
||
;;
|
||
;;======================================================================
|
||
|
||
|
||
|
||
|
||
public InitMem
|
||
InitMem proc near
|
||
push BP
|
||
sub SP,2 ;; Allocate loacl storage
|
||
mov BP,SP
|
||
|
||
mov word ptr [bp+0],0 ;; number of pages allocated
|
||
|
||
mov bx,ds
|
||
mov es,bx ;; ensure ES = DS
|
||
|
||
;; The first eight pagetable entries contain offsets to data within
|
||
;; the local data segment. These offsets must be changed to to
|
||
;; selectors so that they can be accessed as any other scheme object.
|
||
|
||
;; Convert offset within pagetabl[0] into paragraph address
|
||
|
||
mov di,offset pagetabl
|
||
|
||
xor si,si
|
||
mov bx,word ptr [di] ;; si:bx = offset within DS
|
||
xor cx,cx
|
||
mov dx,16 ;; cx:dx = length
|
||
mov ax,0E801h ;; Create Data Window
|
||
int DOS
|
||
jc subsegerr
|
||
mov word ptr [di],ax ;; move selector into pagetabl
|
||
|
||
;; Now convert pagetabl[4] through pagetabl[8]
|
||
|
||
mov dx,5 ;; dx = # entries to modify
|
||
mov di,offset pagetabl[8]
|
||
EmmP$0:
|
||
push dx
|
||
mov bx,word ptr [di] ;; si:bx = offset within ds
|
||
xor cx,cx ;; cx:dx = length
|
||
mov dx,0600h ;; (big enough for largest page)
|
||
mov ax,0E801h ;; Create Data Window
|
||
int DOS
|
||
pop dx ;; get # entries
|
||
jc subsegerr
|
||
mov word ptr [di],ax ;; move selector into pagetabl
|
||
add di,2 ;; address next pagetable entry
|
||
dec dx ;; any remaining?
|
||
jnz EmmP$0 ;; yes, loop
|
||
jmp around_error
|
||
subsegerr:
|
||
lea bx,sub_segerr
|
||
jmp FatalError
|
||
|
||
around_error:
|
||
;; Now we must allocate the remaining memory (to approx. 4mb), and fill
|
||
;; the remaining pagetabl entries with selectors to address each page.
|
||
|
||
;; ask for too much memory, # bytes available will be returned in cx:dx
|
||
mov cx,0ffffh
|
||
mov dx,0ffffh ;; cx:dx = # bytes requested
|
||
mov ax,0E800h ;; create data segment
|
||
int 021h ;; extended dos function from AIA
|
||
|
||
mov ax,dx
|
||
mov dx,cx ;; dx:ax = # bytes available
|
||
push ax
|
||
push dx ;; save for later
|
||
|
||
;; calculate #paragraphs available
|
||
mov cx,4 ;; cx = shift count
|
||
make_para:
|
||
shr dx,1
|
||
rcr ax,1
|
||
loop make_para
|
||
;; lets make the pagesize a multiple of 2000h bytes (this is so that when
|
||
;; pages must be merged to hold large objects, there will be no wasted
|
||
;; space).
|
||
mov cx,NUMPAGES-PreAlloc ;; cx = number pagetabl entrys available
|
||
idiv cx
|
||
mov bx,ax ;; bx = # paras per page
|
||
mov ax,200h
|
||
cmp ax,bx ;; if #paras/page < 200 paras
|
||
jge make_pagesize ;; round to 200, jump
|
||
mov ax,400h ;; if #paras/page < 400 paras
|
||
cmp ax,bx ;; round to 400, jump
|
||
jge make_pagesize
|
||
mov ax,7FFh ;; default pagesize to 7FF0 bytes
|
||
;; change the paras used in calculations above to bytes
|
||
make_pagesize:
|
||
mov cx,4
|
||
shl ax,cl ;; dx = number bytes per page
|
||
mov pagesize,ax ;; save away in pagesize
|
||
;; divide the # bytes available by the #bytes/page to see how many
|
||
;; pages will be required. max = NUMPAGES-PreAlloc
|
||
mov cx,ax ;; cx = # bytes/page
|
||
pop dx
|
||
pop ax ;; dx:ax = # bytes available
|
||
idiv cx ;; ax = # pages required
|
||
cmp ax,NUMPAGES-PreAlloc ;; do we exceed number avail page?
|
||
jle Emmp$0a ;; no, jump
|
||
mov ax,NUMPAGES-PreAlloc ;; yes, just fill the table
|
||
Emmp$0a:
|
||
xor dx,dx
|
||
mul cx ;; dx:ax = total memory rquirements
|
||
|
||
;; Allocate only enough memory for the pagetable. Initially allocate just
|
||
;; one segment large enough to hold all the scheme heap.
|
||
push cx ;;tempsave bytes/page
|
||
mov cx,dx
|
||
mov dx,ax ;; cx:dx = length
|
||
mov ax,0E800h ;; Create Data Segment
|
||
int DOS
|
||
pop bx ;;restore bytes/page
|
||
jnc Emmp$0b
|
||
allocerr:
|
||
lea bx,alloc_err
|
||
jmp FatalError
|
||
Emmp$0b:
|
||
mov scheme_heap,ax ;; save selector to scheme heap
|
||
|
||
;; Now allocate multiple "windows" within this larger segment. The pages
|
||
;; may overlap so that we can merge pages to hold objects that are larger
|
||
;; than a single page. In AI Archiects terminology, we will allocate
|
||
;; "pages" of 8000h (large enough for our largest object) with a "stride"
|
||
;; of our desired pagesize (this causes overlap every pagesize number of
|
||
;; bytes. The call below will return a selector to the starting page,
|
||
;; and the number of selectors necessary to cover the entire segment.
|
||
;;
|
||
;; Warning: ds register does not address our data segment below
|
||
;;
|
||
mov ds,ax ;; ds = large segment
|
||
xor cx,cx
|
||
mov dx,08000h ;; cx:dx = size of each page
|
||
xor si,si ;; si:bx = stride
|
||
push bx ;; save page size
|
||
mov AX,0EA00h ;; Allocate Multiple Windows
|
||
int DOS ;; extended Dos func from AIA
|
||
pop si ;; restore page size
|
||
push ss
|
||
pop ds
|
||
jc allocerr ;; if error, exit
|
||
;;
|
||
;; Warning: ds register does not address our data segment above
|
||
;;
|
||
;; ax = first selector, bx = number of selectors, si=page size
|
||
;; loop number of selector times, filling the pagetabl with
|
||
;; selectors to the memory. selectors are 8 bytes in length
|
||
;; so bump each selector by 8 to get to the next one.
|
||
|
||
mov dx,nextpage ;; Next page table entry
|
||
mov freepage,dx ;; is also next free page
|
||
mov first_pa,dx ;; save for rlsexp, sbid
|
||
mov cx,bx ;; cx = number of pages to fill
|
||
jcxz Emmp$2 ;; if no pages, jump
|
||
EmmP$1:
|
||
mov bx,dx
|
||
shl bx,1 ;; bx = page index
|
||
mov word ptr ss:pagetabl[BX],AX ;; Save selector in table
|
||
and word ptr ss:attrib[BX],not NOMEMORY ;; mark as allocated
|
||
mov word ptr ss:psize[BX],si ;; note its size
|
||
inc dx ;; and update for next page
|
||
mov word ptr ss:pagelink[BX],dx ;; update page link
|
||
mov word ptr ss:nextcell[BX],0 ;; clear free chain pointer
|
||
inc word ptr [bp+0] ;; page_count++
|
||
add ax,8 ;; next selector
|
||
loop EmmP$1 ;; get next selector
|
||
EmmP$2:
|
||
mov nextpage,dx ;; set up nextpage
|
||
mov lastpage,dx ;; lastpage = nextpage
|
||
pop ax ;; return number pages allocated
|
||
pop bp
|
||
ret
|
||
FatalError:
|
||
mov ax,ss ;; ensure ds=es=ss
|
||
mov ds,ax
|
||
mov es,ax
|
||
push bx ;; push error message
|
||
C_call print_an ;; print message and quit
|
||
InitMem endp
|
||
|
||
;;======================================================================
|
||
;;
|
||
;; rlsexp - Release Dos Allocated Pages
|
||
;;
|
||
;;======================================================================
|
||
public rlsexp
|
||
rlsexp proc near
|
||
push ES
|
||
push BP
|
||
mov BP,SP
|
||
mov es,scheme_heap ;; es = slector for scheme heap
|
||
mov AX,4900h ;; free allocated memory
|
||
int DOS ;; do it
|
||
pop BP
|
||
pop ES
|
||
ret
|
||
rlsexp endp
|
||
|
||
prog ends
|
||
|
||
end
|
||
|