pcs/prosmmu.asm

268 lines
7.8 KiB
NASM
Raw Permalink Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

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