windows-nt/Source/XPSP1/NT/base/mvdm/wow16/kernel31/3gmemini.asm
2020-09-26 16:20:57 +08:00

662 lines
16 KiB
NASM

include kernel.inc
include protect.inc
.list
.386p
DataBegin
externB WinFlags
externW hGlobalHeap
externW pGlobalHeap
externW ArenaSel
externD hBmDPMI
externD FreeArenaList
externD FreeArenaCount
externD SelTableStart
externW SelTableLen
externW InitialPages
DataEnd
sBegin INITCODE
assumes CS,CODE
externNP get_physical_address
externNP set_physical_address
externNP set_selector_address32
externNP set_selector_limit32
externNP alloc_arena_header
externNP AssociateSelector32
externNP alloc_data_sel
externNP alloc_data_sel32
externNP GrowHeap
externNP DPMIProc
externFP greserve
GA_ALIGN_BYTES = (((GA_ALIGN+1) SHL 4) - 1)
GA_MASK_BYTES = NOT GA_ALIGN_BYTES
;-----------------------------------------------------------------------;
; get_selector_address32 ;
; ;
; Function to translate return of get_physical_address (DX:AX) into EAX ;
; ;
;-----------------------------------------------------------------------;
cProc get_selector_address32,<PUBLIC,NEAR>
parmW selector
cBegin
push dx
cCall get_physical_address,<selector>
shl eax, 16
mov ax, dx
ror eax, 16
pop dx
cEnd
;-----------------------------------------------------------------------;
; GlobalInit ;
; ;
; Procedure to initialize the global heap. Called with the starting ;
; and ending paragraph addresses. ;
; ;
; Arguments: ;
; parmW hdelta = size (.25k) of master object ;
; parmW palloc = block to mark allocated ;
; = (ROM) Size of DS == allocated block ;
; parmW pstart = first available address ;
; parmW pend = last available address ;
; ;
; Returns: ;
; AX = handle for allocated block ;
; ;
; Error Returns: ;
; ;
; Alters: ;
; ES ;
; Calls: ;
; ginit ;
; hthread ;
; ghalloc ;
; History: ;
; ;
; Sat Jun 20, 1987 05:55:35p -by- David N. Weise [davidw] ;
; Making real EMS work with the fast boot version. ;
; ;
; Sun Mar 15, 1987 06:38:04p -by- David N. Weise [davidw] ;
; Added support for the linked free list long ago. ;
; ;
; Wed Feb 18, 1987 08:09:18p -by- David N. Weise [davidw] ;
; Added the initialization of the gi_alt entries. ;
; ;
; Mon Sep 08, 1986 07:53:41p -by- David N. Weise [davidw ;
; Changed the return values so that this can be called from other than ;
; initialization code. ;
;-----------------------------------------------------------------------;
cProc GlobalInit,<PUBLIC,NEAR>,<ds,si,di>
parmW hdelta
parmW palloc
parmW pstart
parmW pend
localW emspalloc
localW hInitMem
localD allocated_arena
localW next_block
localW free_hi
localW free_lo
cBegin
mov ax,palloc ; AX = block to mark allocated
mov bx,pstart ; BX = first available address
mov cx,hdelta ; CX = size (.25k) of master object
mov dx,pend ; DX = last available address
call ginit
jc FailGlobalInit
SetKernelDS es
mov allocated_arena,eax
xor edi,edi ; Initialize master object
mov [di].phi_first,ebx ; Fill in pointers to first and
mov [di].phi_last,edx ; last blocks
mov [di].hi_count,4 ; 4 arena entries
or eax,eax
jnz short allocated_block
mov [di].hi_count,3 ; 3 arena entries
allocated_block:
mov [di].gi_lruchain,edi ; Nothing in LRU list so far
mov [di].gi_lrucount,di
mov [di].gi_lrulock,di ; ...and not locked
mov [di].gi_reserve,edi ; No discardable code reserve area yet
push eax
mov eax, ds:[edx.pga_address]
mov word ptr [di].gi_disfence,ax ; gi_disfence = hi_last
shr eax, 16
mov word ptr [di].gi_disfence_hi,ax
pop eax
mov [di].gi_alt_first,-1 ; Fill in pointers to first and
mov [di].gi_alt_last,-1 ; last blocks, the -1 is necessary!!
mov [di].gi_alt_count,di ; # of arena entries
mov [di].gi_alt_lruchain,di
mov [di].gi_alt_lrucount,di ; MUST be 0!
mov [di].gi_alt_free_count,di
mov [di].gi_alt_reserve,di
mov [di].gi_alt_disfence,di
mov [di].gi_alt_pPhantom,-1 ; MUST be -1!
mov ax, ds:[esi.pga_handle] ; Pick up master objects selector
mov hGlobalHeap,ax
mov ds:[esi].pga_count,0
mov ds:[esi].pga_selcount,1
if ROM
mov esi,ds:[ebx].pga_next ; in ROM, alloced == first.next
else
mov esi,ds:[edx].pga_prev ; Point to allocated object before
endif
mov bx,ds:[esi.pga_handle]
StoH bx ; It is moveable
mov ds:[esi].pga_handle,bx
mov hInitMem,bx
if ROM
mov ds:[esi].pga_count,1 ; LOCKED in ROM
else
mov ds:[esi].pga_count,0
endif
no_allocated_object:
; initialize free list
mov [di].gi_free_count,1
mov eax,[di].phi_first
mov ecx,[di].phi_last
if ROM
mov ebx,ds:[ecx].pga_prev
else
mov ebx,ds:[eax].pga_next
endif
mov ds:[eax].pga_freeprev,-1 ; Fill in first sentinal
mov ds:[eax].pga_freenext,ebx
mov ds:[ecx].pga_freeprev,ebx ; Fill in last sentinal
mov ds:[ecx].pga_freenext,-1
mov ds:[ebx].pga_freeprev,eax ; Link in free block
mov ds:[ebx].pga_freenext,ecx
pushad
SetKernelDS fs
mov edx, 030000h ; Insist on enough for fence
call GrowHeap
jc short Failed_GrowHeap ;garage sale machine,tough luck!
; 192k (3 segs) fixed greserve
mov ax, 1000h ; fence it all off. (in paras)
push fs
call greserve ; greserve will triple the no.
pop fs
or ax, ax
stc ; assume failure
jz short Failed_GrowHeap
ifdef WOW
clc
; WOW isn't greedy and doesn't have gcommit_block
else
mov esi, ds:[edi].phi_last ; sentinel
mov esi, ds:[esi].pga_prev ; not_there
mov esi, ds:[esi].pga_prev ; free blk
call gcommit_block ; commit it all
jc short Failed_GrowHeap ; to guarantee stable system
; Let's start with 20MB reserve and allocate more as reqd.
mov edx, 20*1024*1024 ; Let's get greedy
call GrowHeap
clc ; we don't care about this fail
endif
Failed_GrowHeap:
UnSetKernelDS fs
popad
jc short FailGlobalInit
mov ax,hInitMem
clc
FailGlobalInit:
cEnd
;-----------------------------------------------------------------------;
; ginit ;
; ;
; Procedure to initialize the global heap. ;
; ;
; The global heap looks as follows after this procedure returns: ;
; ;
; BX - first object in arena, alway busy, zero length. ;
; - free object ;
; AX - allocated object ;
; DS - master object ;
; DX - last object in arena, alway busy, zero length. ;
; ;
; ;
; Arguments: ;
; AX = address of block to mark allocated. May be zero. ;
; = (ROM) length of allocated block (which is DS) ;
; BX = address of first paragraph in arena ;
; DX = address of last paragraph in arena ;
; CX = initial size of master object, in bytes ;
; ;
; Returns: ;
; AX = aligned address of block marked allocated. ;
; BX = aligned address of first object in arena ;
; CX = size of master object, in bytes ;
; DX = aligned address of last object in arena ;
; DS = aligned address of master object ;
; ;
; Registers Preserved: ;
; ;
; Registers Destroyed: ;
; DI,SI,ES ;
; Calls: ;
; nothing ;
; History: ;
; ;
; Thu Sep 11, 1986 04:22:02p -by- David N. Weise [davidw] ;
; Commented it, made it handle the case of no allocated block correctly.;
;-----------------------------------------------------------------------;
assumes ds, nothing
assumes es, nothing
cProc ginit,<PUBLIC,NEAR>
localD size_free
localD size_allocated
localD size_master
localD allocated_arena
localW allocated_sel
localD BurgerMaster_arena
localW BurgerMaster_sel
localD new_last_arena
cBegin
; ESI = the first block address (sentinel, always busy)
SetKernelDS es
push ax
cCall get_selector_address32,<bx> ; Start of our memory
add eax, GA_ALIGN_BYTES ; Align our start
and al, GA_MASK_BYTES
push eax ; Save the start address
cCall set_selector_address32,<bx,eax> ; This will be our arena list
mov ArenaSel, bx
mov BurgerMaster_sel, bx
mov si, bx
push bx
push di
xor bx, bx ; # physical pages available
sub sp, 30h
mov di, sp
push es
smov es, ss
DPMICALL 0500h
pop es
mov eax, 16*1024 ; Size of selector table
jc short default_sel_table
mov bx, word ptr ss:[di][10h]
cmp bx, 256
jb short default_sel_table
;;;mov eax, 31*1024
mov eax, 32*1024
default_sel_table:
mov [InitialPages], bx
; For WOW we assume 386 Kernel is running on paging System
; So always set WF1_PAGING
ifndef WOW
mov ecx, ss:[di][20h] ; Paging file size
inc ecx
cmp ecx, 1 ; 0 or -1?
jbe short @F
endif
or byte ptr WinFlags[1], WF1_PAGING
@@:
mov ecx, ss:[di][0]
shr ecx, 7 ; Bytes reserved for arenas
add sp, 30h
pop di
pop bx
add ecx, GA_ALIGN_BYTES ; Align length of arena table
and cl, GA_MASK_BYTES
add eax, GA_ALIGN_BYTES ; Align length of selector table
and al, GA_MASK_BYTES
mov SelTableLen, ax
cmp ecx, DEFAULT_ARENA_SIZE ; Number of bytes of arenas
jae short @F
mov ecx, DEFAULT_ARENA_SIZE
@@:
mov ebx, Size GlobalInfo+GA_ALIGN_BYTES
and bl, GA_MASK_BYTES ; EBX start of arenas
mov size_master, ebx
add ecx, ebx
mov SelTableStart, ecx
add eax, ecx ; EAX total length of segment
push ecx
push ebx
push eax
push si
mov cx, ax ; Make BX:CX required
mov ebx, eax ; length of Burgermaster
shr ebx, 16
push bx ; Save length
push cx
DPMICALL 0501h
mov hBmDPMI[0], di ; Save DPMI handle
mov hBmDPMI[2], si
pop di ; SI:DI now length
pop si
jc Failginit
if 0
mov di, 4096 ; Lock first page
xor si, si
DPMICALL 0600h ; Now page lock it
push bx
push cx
add cx, word ptr SelTableStart
adc bx, 0
and cx, not 4095
DPMICALL 0600h
pop cx
pop bx
endif
shl ebx, 16
mov bx, cx ; Address in EBX
pop si
pop eax
cCall set_selector_address32,<si,ebx>
mov edi, ebx
;;; cCall set_selector_limit32, <si,eax>
push eax
push dx
dec eax
mov ecx, eax ; Limit in CX:DX
shr ecx, 16
mov dx, ax
test cx,0fff0h ; bits 20-31 set?
jz @F ; No.
or dx,0fffh ; Yes, page align limit.
@@:
mov bx, si ; Selector in BX
DPMICALL 8
pop dx
pop eax
pop ebx
pop ecx
jc Failginit
mov ds, si
sub ecx, ebx ; Subtract out BurgerMaster
cCall InitialiseArenas,<ebx,ecx>
mov ecx, eax
pop esi ; Sentinel address
cCall alloc_arena_header,<esi> ; Sentinel
mov esi, eax
cCall alloc_arena_header,<edi> ; BurgerMaster
mov BurgerMaster_arena, eax
mov ds:[eax].pga_handle, ds ; Save selector in handle field
mov ds:[eax].pga_size, ecx
push edi
push ecx
movzx ecx, SelTableLen
mov edi, SelTableStart
push es
smov es, ds ; Zero this area
UnSetKernelDS es
shr ecx, 2
xor eax, eax
rep stos dword ptr es:[edi]
pop es
ReSetKernelDS es
pop ecx
pop edi
cCall AssociateSelector32,<ds,BurgerMaster_Arena> ; Set back link
; EDI = the Free block address (initial free block)
ife ROM
mov eax, ds:[esi].pga_address
;;; add eax, ecx
cCall alloc_arena_header,<eax>
mov edi, eax ; Free block arena in EDI
movzx eax, dx ; Get linear address
shl eax, 4
else
cCall get_selector_address32, <dx>
endif
; EDX = the last block address (sentinel, always busy)
and al, GA_MASK_BYTES
push eax
cCall alloc_arena_header,<eax>
mov new_last_arena, eax ; Save it away
pop ebx
if ROM
; in ROM, the alloced segment is the data segment, and we are
; passed the length, not the address
;
; the length (a word) is on the stack from that very first push way
; up there, and we want the base in eax and the length in ebx
;
CheckKernelDS ES
cCall get_selector_address32, <es>
and al, GA_MASK_BYTES
xor ebx, ebx ; clear hi word of length
pop bx
add ebx, GA_ALIGN_BYTES
and bl, GA_MASK_BYTES
cCall set_selector_limit32, <es, ebx>
else
pop ax ; Allocated Block
cCall get_selector_address32, <ax>
and al, GA_MASK_BYTES ; "Align" it
sub ebx, eax ; Length in bytes
endif
ife ROM
push eax
endif
push eax
cCall alloc_arena_header, <eax>
mov ds:[eax].pga_size, ebx ; Record size
mov allocated_arena, eax
mov ebx, eax
pop eax
if ROM
CheckKernelDS ES
mov allocated_sel, es
mov ds:[ebx.pga_handle], es
cCall AssociateSelector32,<es, ebx>
else
cCall alloc_data_sel32, <eax, ds:[ebx].pga_size>
mov allocated_sel, ax
mov ds:[ebx.pga_handle], ax ; Save selector
cCall AssociateSelector32,<ax,ebx> ; Set back link
endif
if ROM
; now deal with the free one
mov eax, ds:[ebx].pga_address
add eax, ds:[ebx].pga_size
add eax, GA_ALIGN_BYTES
and al, GA_MASK_BYTES
cCall alloc_arena_header, <eax>
mov edi, eax
cCall get_selector_address32, <dx>
mov ebx, eax
else
pop ebx
endif
sub ebx, ds:[edi].pga_address ; Length in bytes
mov ds:[edi].pga_size, ebx
mov eax, allocated_arena
mov ecx, BurgerMaster_arena
mov edx, new_last_arena
; Fill in first block
xor ebx, ebx
mov ds:[esi].pga_sig,GA_SIGNATURE
mov ds:[esi].pga_size,ebx
mov ds:[esi].pga_owner,-1
mov ds:[esi].pga_flags,bx
mov ds:[esi].pga_prev,esi ; first.prev = self
if ROM
mov ds:[esi].pga_next,eax ; first.next = alloced (ds)
else
mov ds:[esi].pga_next,edi ; first.next = free
endif
mov ds:[esi].pga_handle,bx
mov ds:[esi].pga_lrunext,ebx
mov ds:[esi].pga_lruprev,ebx
; Fill in the last block (sentinel block)
mov ds:[edx].pga_sig,GA_ENDSIG
mov ds:[edx].pga_size,ebx
mov ds:[edx].pga_owner,-1 ; Always allocated
mov ds:[edx].pga_next,edx ; last.next = self
if ROM
mov ds:[edx].pga_prev,edi ; last.prev = free
else
mov ds:[edx].pga_prev,eax ; last.prev = alloced
endif
mov ds:[edx].pga_flags,bx
mov ds:[edx].pga_handle, bx
mov ds:[edx].pga_lrunext,ebx
mov ds:[edx].pga_lruprev,ebx
; Fill in the master object
mov ds:[ecx].pga_next,ecx
mov ds:[ecx].pga_prev,ecx
mov ds:[ecx].pga_sig,GA_SIGNATURE
mov ds:[ecx].pga_owner,-3
mov ds:[ecx].pga_flags,bx
mov ds:[ecx].pga_lruprev,ebx
mov ds:[ecx].pga_lrunext,ebx
; Fill in the allocated block
if ROM
mov ds:[eax].pga_next,edi ; next = free
mov ds:[eax].pga_prev,esi ; prev = first
else
mov ds:[eax].pga_next,edx ; next object is Sentinel
mov ds:[eax].pga_prev,edi ; Previous object is second block
endif
mov ds:[eax].pga_sig,GA_SIGNATURE
mov ds:[eax].pga_owner,-1
mov ds:[eax].pga_flags,bx
mov ds:[eax].pga_lruprev,ebx
mov ds:[eax].pga_lrunext,ebx
; Fill in free block
mov ds:[edi].pga_sig,GA_SIGNATURE
mov ds:[edi].pga_owner,bx ; This is a free block
mov ds:[edi].pga_flags,bx
if ROM
mov ds:[edi].pga_next,edx ; next = last
mov ds:[edi].pga_prev,eax ; prev = alloced
else
mov ds:[edi].pga_next,eax ; Next obj allocated block
mov ds:[edi].pga_prev,esi
endif
mov ds:[edi].pga_handle,bx
mov ds:[edi].pga_lruprev,ebx
mov ds:[edi].pga_lrunext,ebx
; Initialize master object
mov ecx, size_master
mov dx,BurgerMaster_sel
shr ecx, 1
push ecx ; save size in words
mov pGlobalHeap,dx
mov es,dx
UnSetKernelDS es
xor eax,eax
xor di,di ; Init master object to zero
shr ecx, 1
rep stosd
mov ds,dx ; Switch to master object as our DS
pop ecx
shl ecx,1 ; ECX = size of master object in bytes
mov eax, allocated_arena ; EAX = address of allocated block
mov edx, new_last_arena ; EDX = address of last block
mov ebx, esi ; EBX = address of first block
mov esi, BurgerMaster_arena ; ESI = arena of BurgerMaster
clc
Failginit:
cEnd
assumes ds, nothing
assumes es, nothing
cProc InitialiseArenas,<PUBLIC,NEAR>
parmD StartOffset
parmD BytesAllocated
cBegin
push ecx
push esi
push edi
CheckKernelDS es
ReSetKernelDS es
mov esi, StartOffset
mov ecx, BytesAllocated
add ecx, esi
mov FreeArenaList, esi ; Point to list
lea edi, [esi+size GlobalArena32]
IA_loop:
cmp edi, ecx
jae short IA_done
mov [esi.pga_next], edi
add esi, size GlobalArena32
add edi, size GlobalArena32
inc FreeArenaCount
jmps IA_loop
IA_done:
mov ds:[esi.pga_next], -1 ; Terminate list
UnSetKernelDS es
pop edi
pop esi
pop ecx
cEnd
sEnd INITCODE
end