Tvùrce webu je i pro tebe! Postav tøeba web. Bez grafika. Bez kodéra. Hned.
wz

VIRTMEM.ASM

Virtual Memory


; =============================================================================
;
;                            Litos - Virtual memory
;
; =============================================================================

		CODE_SECTION	32

; -----------------------------------------------------------------------------
;         Callback function to compare virtual memory region by address
; -----------------------------------------------------------------------------
; INPUT:	EAX = address to search for
;		EBX = region to test
; OUTPUT:	ZY = region matches, CY = address is below region
; -----------------------------------------------------------------------------

VirtMemCBAddr:	cmp	eax,[ebx+VMR_Start] ; compare start address
		jb	VirtMemCBAddr4	; address is below region
		cmp	eax,[ebx+VMR_End] ; compare end address
		ja	VirtMemCBAddr4	; address is above region
		cmp	eax,eax		; region is ok, set ZY flag
VirtMemCBAddr4:	ret

; -----------------------------------------------------------------------------
;                    Find region in virtual memory by address
; -----------------------------------------------------------------------------
; INPUT:	EAX = address to search for
;		EDX = virtual memory descriptor
; OUTPUT:	EBX = virtual memory region (or NULL if region not found)
;		CY = region not found (EBX = 0)
; NOTES: Region which contains given address will be found.
; -----------------------------------------------------------------------------

; ------------- Push registers

VirtMemFindAddr:push	esi		; push ESI
		mov	esi,VirtMemCBAddr ; ESI <- callback compare function

; ------------- Use cache

		mov	ebx,[edx+VMD_Cache] ; EBX <- cache region
		or	ebx,ebx		; is cache region valid?
		jz	VirtMemFindAdr2	; cache region is not valid
		call	esi		; check cached region
		je	VirtMemFindAdr4	; region suits

; ------------- Find region

VirtMemFindAdr2:call	RBTreeSrcFnc	; find region
		jc	VirtMemFindAdr4	; region not found
		mov	[edx+VMD_Cache],ebx ; save found region into cache

; ------------- Pop registers

VirtMemFindAdr4:pop	esi		; pop ESI
		ret

; -----------------------------------------------------------------------------
;    Callback function to compare virtual memory higher region by address
; -----------------------------------------------------------------------------
; INPUT:	EAX = address to search for
;		EBX = region to test
; OUTPUT:	ZY = region matches, CY = address is below region
; -----------------------------------------------------------------------------

VirtMemCBHigh:	cmp	eax,[ebx+VMR_End] ; compare end address
		ret

; -----------------------------------------------------------------------------
;              Find nearest higher region in virtual memory by address
; -----------------------------------------------------------------------------
; INPUT:	EAX = address to search for
;		EDX = virtual memory descriptor
; OUTPUT:	EBX = virtual memory region (or NULL if region not found)
;		CY = region not found (EBX = 0)
; NOTES: Nearest higher or equal region will be found.
; -----------------------------------------------------------------------------

; ------------- Push registers

VirtMemFindHigh:push	esi		; push ESI

; ------------- Use cache

		mov	ebx,[edx+VMD_Cache] ; EBX <- cache region
		or	ebx,ebx		; is cache region valid?
		jz	VirtMemFindHgh2	; cache region is not valid
		call	VirtMemCBAddr	; check cached region
		je	VirtMemFindHgh4	; region suits

; ------------- Find region

VirtMemFindHgh2:mov	esi,VirtMemCBHigh ; ESI <- callback compare function
		call	RBTreeSrcHigh	; find nearest higher region
		jc	VirtMemFindHgh4	; region not found
		mov	[edx+VMD_Cache],ebx ; save found region into cache

; ------------- Pop registers

VirtMemFindHgh4:pop	esi		; pop ESI
		ret

; -----------------------------------------------------------------------------
;      Find first region in virtual memory that overlaps a given interval
; -----------------------------------------------------------------------------
; INPUT:	EAX = start address of the interval (=address of first byte)
;		ECX = end address of the interval (=address of last byte)
;		EDX = virtual memory descriptor
; OUTPUT:	EBX = virtual memory region (or NULL if region not found)
;		CY = region not found (EBX = 0)
; -----------------------------------------------------------------------------

VirtMemFindInt:	call	VirtMemFindHigh	; find nearest higher region
		jc	VirtMemFindInt8	; region not found
		cmp	ecx,[ebx+VMR_Start] ; check start address of interval
		jae	VirtMemFindInt8	; interval found OK
		xor	ebx,ebx		; EBX <- invalid region
		stc			; set error flag, region not found
VirtMemFindInt8:ret

; -----------------------------------------------------------------------------
;           Check free space in virtual memory with a given address
; -----------------------------------------------------------------------------
; INPUT:	EAX = required start address
;		ECX = required size
;		EDX = virtual memory descriptor
; OUTPUT:	EAX = start address of the region rounded down to page size
;		ECX = new size of the region rounded up to page size
;		CY = region not found (address and size may be rounded)
; -----------------------------------------------------------------------------

; ------------- Push registers

VirtMemGetAddr:	push	ebx		; push EBX
		push	esi		; push ESI

; ------------- Check address and size of the region

		cmp	eax,SYSTEM_ADDR	; maximal address of region
		jae	VirtMemGetAddr8	; invalid address of region
		cmp	ecx,SYSTEM_ADDR	; maximal size of region
		jae	VirtMemGetAddr8	; invalid size of region

; ------------- Round address down to page boundary

		mov	ebx,eax		; EBX <- start address
		and	ebx,(PAGE_SIZE-1) ; EBX = offset in a page
		add	ecx,ebx		; ECX <- size correction
		and	eax,PAGE_MASK	; round address to page boundary

; ------------- Round size up to page boundary

		add	ecx,PAGE_SIZE-1	; round up
		and	ecx,PAGE_MASK	; round size to page boundary

; ------------- Prepare end address of the region (-> ESI)

		mov	esi,eax		; ESI <- start address of the region
		add	esi,ecx		; ESI <- end address of the region+1
		jc	VirtMemGetAddr9	; invalid end address
		dec	esi		; ESI <- end address (=last byte)
		cmp	esi,SYSTEM_ADDR	; check end address of the region
		jae	VirtMemGetAddr8	; invalid end address

; ------------- Check free space after start address

		call	VirtMemFindHigh	; find nearest higher region (-> EBX)
		jc	VirtMemGetAddr8	; region not found, it's OK
		cmp	esi,[ebx+VMR_Start] ; check start address

; ------------- Pop registers

VirtMemGetAddr8:cmc			; invert error flag
VirtMemGetAddr9:pop	esi		; pop ESI
		pop	ebx		; pop EBX
		ret

; -----------------------------------------------------------------------------
;                      Find free space in virtual memory
; -----------------------------------------------------------------------------
; INPUT:	EAX = required starting address
;			use:	0 = start of virtual space
;				VIRTMEM_MID = middle of virtual space
;				-1 (or SYSTEM_ADDR) = end of virtual space
;		EBX = flags
;			no flag: precise start address required
;			VMR_FINDUP: search free region up
;			VMR_FINDDOWN: search free region down
;			both flags: nearest region in up or down direction
;		ECX = required size
;		EDX = virtual memory descriptor
; OUTPUT:	EAX = start address of the region (rounded to page size)
;		ECX = new size of the region (rounded to page size)
;		CY = region not found (address and size may be rounded+limited)
; -----------------------------------------------------------------------------

; ------------- Find region with precise address

VirtMemGetReg:	test	ebx,VMR_FINDUP|VMR_FINDDOWN ; any flag?
		jz	short VirtMemGetAddr ; find area with precise address
		
; ------------- Find region in up direction

		test	ebx,VMR_FINDDOWN ; down direction required?
		jz	short VirtMemGetUp ; find area in up direction

; ------------- Find region in down direction

		test	ebx,VMR_FINDUP	; up direction required?
		jz	near VirtMemGetDown ; find area in down direction

; ------------- Push registers

		push	ebx		; push EBX
		push	esi		; push ESI
		push	edi		; push EDI

; ------------- Find region in up direction

		mov	esi,eax		; ESI <- required address
		mov	ebx,eax		; EBX <- required address
		call	VirtMemGetUp	; find region in up direction
		xchg	eax,esi		; EAX <- old address,ESI <- new address
		jnc	VirtMemGetReg2	; region found OK

; ------------- No region in up direction, find region in down direction

		call	VirtMemGetDown	; find region in down direction
		jmp	short VirtMemGetReg8

; ------------- Find region in down direction

VirtMemGetReg2:	call	VirtMemGetDown	; find region in down direction
		jc	VirtMemGetReg6	; region in down direction not found

; ------------- Check nearest region

VirtMemGetReg4:	mov	edi,esi		; EDI <- region in up direction
		sub	edi,ebx		; EDI <- distance in up direction
		sub	ebx,eax		; EBX <- distance in down direction
		cmp	edi,ebx		; is up region nearer?
		jb	VirtMemGetReg7	; no, use region in down direction

; ------------- Use region in up direction

VirtMemGetReg6:	xchg	eax,esi		; EAX <- address in up direction
VirtMemGetReg7:	clc			; clear error flag
		
; ------------- Pop registers

VirtMemGetReg8:	pop	edi		; pop EDI
		pop	esi		; pop ESI
		pop	ebx		; pop EBX
		ret

; -----------------------------------------------------------------------------
;               Find free space in virtual memory in up direction
; -----------------------------------------------------------------------------
; INPUT:	EAX = minimal address of start of the region
;		ECX = required size
;		EDX = virtual memory descriptor
; OUTPUT:	EAX = start address of the region
;		ECX = new size of the region rounded up to page size
;		CY = region not found (address and size may be rounded)
; -----------------------------------------------------------------------------

; ------------- Push registers

VirtMemGetUp:	push	ebx		; push EBX
		push	esi		; push ESI

; ------------- Basic check address and size of the region

		cmp	eax,SYSTEM_ADDR	; maximal address of region
		jae	VirtMemGetUp8	; invalid address of region
		cmp	ecx,SYSTEM_ADDR	; maximal size of region
		jae	VirtMemGetUp8	; invalid size of region

; ------------- Round address up to page boundary

		add	eax,PAGE_SIZE-1	; round up
		and	eax,PAGE_MASK	; round address to page boundary

; ------------- Round size up to page boundary

		add	ecx,PAGE_SIZE-1	; round up
		and	ecx,PAGE_MASK	; round size to page boundary

; ------------- Prepare end address of the region (-> ESI)

		mov	esi,eax		; ESI <- start address of the region
		add	esi,ecx		; ESI <- end address of the region+1
		jc	VirtMemGetUp9	; invalid end address
		dec	esi		; ESI <- end address (=last byte)

; ------------- Find nearest higher region

		call	VirtMemFindHigh	; find nearest high region
		jc	VirtMemGetUp6	; no region found

; ------------- Check remaining free space		

VirtMemGetUp4:	cmp	esi,[ebx+VMR_Start] ; check free space
		jb	VirtMemGetUp8	; region is OK
		mov	esi,[ebx+VMR_End] ; ESI <- end address of the region
                add	esi,ecx		; ESI <- end address of the region
		jc	VirtMemGetUp9	; invalid end address
		
; ------------- Get next region

		call	RBTreeNext	; get next region
		jnc	VirtMemGetUp4	; other region have been found

; ------------- Check end address of virtual memory

VirtMemGetUp6:	cmp	esi,SYSTEM_ADDR	; check end address of the region

; ------------- Get start address of the region (-> EAX)

VirtMemGetUp8:	cmc			; invert error flag
		jc	VirtMemGetUp9	; region not found
		xchg	eax,esi		; EAX <- end address of the region
		inc	eax		; EAX <- end address + 1
		sub	eax,ecx		; EAX <- start address of the region

; ------------- Pop registers

VirtMemGetUp9:	pop	esi		; pop ESI
		pop	ebx		; pop EBX
		ret

; -----------------------------------------------------------------------------
;              Find free space in virtual memory in down direction
; -----------------------------------------------------------------------------
; INPUT:	EAX = maximal address of start of the region
;		ECX = required size
;		EDX = virtual memory descriptor
; OUTPUT:	EAX = start address of the region
;		ECX = new size of the region rounded up to page size
;		CY = region not found (address and size may be rounded+limited)
; -----------------------------------------------------------------------------

; ------------- Push registers

VirtMemGetDown:	push	ebx		; push EBX
		push	esi		; push ESI

; ------------- Basic check size of the region

		cmp	ecx,SYSTEM_ADDR	; maximal size of region
		jae	VirtMemGetDwn8	; invalid size of region

; ------------- Round size up to page boundary

		add	ecx,PAGE_SIZE-1	; round up
		and	ecx,PAGE_MASK	; round size to page boundary

; ------------- Limit start address

		mov	ebx,SYSTEM_ADDR ; EBX <- system address
		sub	ebx,ecx		; EBX <- maximal start address
		cmp	eax,ebx		; is start address OK?
		jb	VirtMemGetDwn2	; start address is OK
		xchg	eax,ebx		; EAX <- limit start address
VirtMemGetDwn2:	and	eax,PAGE_MASK	; round address to page boundary

; ------------- Find nearest higher region

		mov	esi,eax		; ESI <- start address of the region
		call	VirtMemFindHigh	; find nearest high region
		jc	VirtMemGetDwn8	; no region have been found, it's OK

; ------------- Check remaining free space		

		add	esi,ecx		; ESI <- end address of the region+1
		cmp	[ebx+VMR_Start],esi ; check free space
		jae	VirtMemGetDwn9	; region is OK

; ------------- Address of previous free region

VirtMemGetDwn4:	mov	esi,[ebx+VMR_Start] ; ESI <- start address of region
		sub	esi,ecx		; ESI <- start address of free space
		jc	VirtMemGetDwn9	; underflow

; ------------- Get previous region

		call	RBTreePrev	; get previous region
		jc	VirtMemGetDwn8	; no previous region, free space is OK

; ------------- Check free space

		cmp	[ebx+VMR_End],esi ; check end address of the region
		jae	VirtMemGetDwn4	; region overlaps checked free space

; ------------- Get start address of the region (-> EAX)

VirtMemGetDwn8:	cmc			; invert error flag
		jc	VirtMemGetDwn9	; region not found
		xchg	eax,esi		; EAX <- start address of the region

; ------------- Pop registers

VirtMemGetDwn9:	pop	esi		; pop ESI
		pop	ebx		; pop EBX
		ret

; -----------------------------------------------------------------------------
;                  Insert virtual memory region into memory map
; -----------------------------------------------------------------------------
; INPUT:	EAX = virtual memory region VMREG
;			(start and end pointers must be filled up)
;		EDX = virtual memory descriptor
; OUTPUT:	CY = region overlaps with other regions in memory map
;		EBX = pointer to existing entry (if CY) or new entry (=EAX)
; NOTES: Inserted region must not overlap other regions in memory map.
; -----------------------------------------------------------------------------

; ------------- Push registers

VirtMemInsReg:	push	esi		; push ESI

; ------------- Insert region

		mov	esi,VirtMemCBAddr ; ESI <- callback compare function
		call	RBTreeInsert	; insert region into memory map

; ------------- Pop registers

		pop	esi		; pop ESI
		ret

; -----------------------------------------------------------------------------
;                 Lock file mapping in virtual memory region
; -----------------------------------------------------------------------------

VirtMemRegLock:	

; TODO !!!!!!!!!!!

		ret

; -----------------------------------------------------------------------------
;                 Unlock file mapping in virtual memory region
; -----------------------------------------------------------------------------

VirtMemRegUnlock:	

; TODO !!!!!!!!!!!

		ret

; -----------------------------------------------------------------------------
;                 Remove shared virtual memory region from file mapping
; -----------------------------------------------------------------------------

VirtMemRegUnshare:

; TODO !!!!!!!!!!!

		ret

; -----------------------------------------------------------------------------
;                      Deallocate virtual memory (without lock)
; -----------------------------------------------------------------------------
; INPUT:	EAX = start address of the interval
;		ECX = size of the interval
;		EDX = virtual memory descriptor
; -----------------------------------------------------------------------------

; ------------- Push registers

VirtMemFree:	push	eax		; push EAX
		push	ebx		; push EBX
		push	ecx		; push ECX
		push	esi		; push ESI
		push	edi		; push EDI

; ------------- Get current task (-> EDI)

		CURRENT	edi		; EDI <- get current task

; ------------- Limit start address

		cmp	eax,SYSTEM_ADDR	; check start address
		jb	VirtMemFree2	; address is OK
		mov	eax,SYSTEM_ADDR	; limit start address

; ------------- Round address down to page boundary (-> EAX)

VirtMemFree2:	mov	ebx,eax		; EBX <- start address
		and	ebx,(PAGE_SIZE-1) ; EBX = offset in a page
		and	eax,PAGE_MASK	; round address to page boundary
		add	ecx,ebx		; ECX <- size correction
		jc	VirtMemFree22	; overflow

; ------------- Limit size of the interval (-> ECX)

		mov	ebx,ecx		; EBX <- size of the interval
		add	ebx,eax		; EBX <- end of the interval
		jc	VirtMemFree22	; overflow
		cmp	ebx,SYSTEM_ADDR	; check end
		jbe	VirtMemFree23	; size is OK
VirtMemFree22:	mov	ecx,SYSTEM_ADDR	; ECX <- end of virtual space
		sub	ecx,eax		; ECX <- limited size of the interval
VirtMemFree23:	add	ecx,PAGE_SIZE-1	; round up
		and	ecx,PAGE_MASK	; round size to page boundary

; ------------- Invalidate region cache

		and	dword [edx+VMD_Cache],byte 0 ; invalidate region cache

; ------------- Find nearest high region (-> EBX)

		call	VirtMemFindHigh	; find nearest high region
		jc	VirtMemFree9	; no other region

; ------------- Check if this region overlaps with the interval

VirtMemFree3:	mov	esi,eax		; ESI <- start of the interval
		add	esi,ecx		; ESI <- end of the interval+1
		cmp	esi,[ebx+VMR_Start] ; does region fall into interval?
		jbe	VirtMemFree9	; region does not fall into interval

; ------------- Test if "hole" splits region into two parts

		cmp	eax,[ebx+VMR_Start] ; test start of interval
		jbe	VirtMemFree4	; no splitting
		cmp	esi,[ebx+VMR_End] ; test end of interval
		ja	VirtMemFree4	; no splitting

; ------------- Check maximal number of regions

		mov	esi,[edx+RBR_Count] ; current number of regions
		cmp	esi,[edi+TASK_ResLim+RL_VirtMemReg] ; check regions
		jae	VirtMemFree9	; number of regions exceeded

; ------------- Remove shared region from file mapping

VirtMemFree4:	call	VirtMemRegUnshare ; remove shared region from mapping

; ------------- Push registers 2

		push	eax		; push EAX (start of the interval)
		push	ecx		; push ECX (size of the interval)

; ------------- Prepare end of deleted part of region (-> ECX)

		add	ecx,eax		; ECX <- end of the interval+1
		dec	ecx		; ECX <- end of the interval
		cmp	ecx,[ebx+VMR_End] ; end of region exceeded?
		jbe	VirtMemFree52	; end of interval is OK
		mov	ecx,[ebx+VMR_End] ; ECX <- new end of the interval

; ------------- Prepare start of deleted part of region (-> EAX)

VirtMemFree52:	cmp	eax,[ebx+VMR_Start] ; does interval start below region?
		ja	VirtMemFree56	; it does not start below region
		mov	eax,[ebx+VMR_Start] ; limit start of the interval

; ------------- Free whole region
		
		cmp	ecx,[ebx+VMR_End] ; end of region?
		jne	VirtMemFree54	; not equal
		mov	eax,ebx		; EAX <- memory region
		call	RBTreePrev	; EBX <- previous memory region
		call	VirtMemRegFree	; free virtual memory region
		jmp	short VirtMemFree8

; ------------- Delete start of region

VirtMemFree54:	mov	[ebx+VMR_Start],ecx ; new start of region
		jmp	short VirtMemFree8

; ------------- Delete end of region

VirtMemFree56:	cmp	ecx,[ebx+VMR_End] ; end of region?
		jne	VirtMemFree58	; not equal
		mov	[ebx+VMR_End],eax ; new end of region
		jmp	short VirtMemFree8

; ------------- Delete middle of region

VirtMemFree58:	xchg	eax,esi		; ESI <- save start of "hole"		
		call	VirtMemRegAlloc	; allocate new memory region
		jc	VirtMemFree8	; memory error
		xchg	esi,[ebx+VMR_End] ; set end of old region, ESI<-old end
		mov	[eax+VMR_End],esi ; set end of new region
		mov	[eax+VMR_Start],ecx ; set start of new region
		sub	ecx,[ebx+VMR_Start] ; ECX <- offset of new region
		add	ecx,[ebx+VMR_Offset] ; ECX <- offset of new region
		mov	[eax+VMR_Offset],ecx ; set offset of new region LOW
		mov	ecx,[ebx+VMR_Offset+4]; ECX <- offset HIGH
		adc	ecx,byte 0	; overflow
		mov	[eax+VMR_Offset+4],ecx ; set offset of new region HIGH
		mov	esi,[ebx+VMR_Flags] ; ESI <- flags of old region
		mov	[eax+VMR_Flags],esi ; set flags of new region
		mov	esi,[ebx+VMR_File] ; ESI <- file of old region
		mov	[eax+VMR_File],esi ; set file of new region
		call	VirtMemInsReg	; insert new region
		xchg	eax,ebx		; EBX <- new region

; ------------- Pop registers 2

VirtMemFree8:	pop	ecx		; pop ECX (size of the interval)
		pop	eax		; pop EAX (start of the interval)

; ------------- Get next region

		call	RBTreeNext	; get next region
		jnc	VirtMemFree3	; test next region

; ------------- Remove pages from user space

VirtMemFree9:	call	PageRemove	; remove pages from user space

; ------------- Flush CPU page cache

		call	FlushPageCache	; flush CPU page cache

; ------------- Pop registers

		pop	edi		; pop EDI
		pop	esi		; pop ESI
		pop	ecx		; pop ECX
		pop	ebx		; pop EBX
		pop	eax		; pop EAX
		ret

; -----------------------------------------------------------------------------
;                      Deallocate virtual memory (witht lock)
; -----------------------------------------------------------------------------
; INPUT:	EAX = start address of the interval
;		ECX = size of the interval
;		EDX = virtual memory descriptor
; -----------------------------------------------------------------------------

; ------------- Lock virtual memory descriptor

VirtMemFreeLock:pushf			; push flags
		cli			; disable interrupts
%ifdef	SMP
		LOCK_Lock (edx+VMD_Lock) ; lock virtual memory descriptor
%endif

; ------------- Deallocate virtual memory

		call	VirtMemFree	; deallocate virtual memory

; ------------- Unlock virtual memory descriptor
%ifdef	SMP
		LOCK_Unlock (edx+VMD_Lock) ; unlock virtual memory descriptor
%endif
		popf			; pop flags
		ret

; -----------------------------------------------------------------------------
;                      Merge memory region with its neighbour
; -----------------------------------------------------------------------------
; INPUT:	EBX = memory region
;		EDX = virtual memory descriptor
; NOTES: This function doesn't lock virtual memory descriptor.
; -----------------------------------------------------------------------------

; ------------- Push registers

VirtMemMerge:	push	eax		; push EAX
		push	ecx		; push ECX
		push	esi		; push ESI
		push	edi		; push EDI

; ------------- Prepare number of regions to merge

		xor	ecx,ecx		; ECX <- 0
		mov	cl,2		; ECX <- 2, number of regions

; ------------- Prepare current region (-> EBX) and next region (-> ESI)

		mov	esi,ebx		; ESI <- next region
		call	RBTreePrev	; get previous region
		jc	VirtMemMerge6	; no previous region

; ------------- Compare start and end addresses

VirtMemMerge2:	mov	eax,[ebx+VMR_End] ; EAX <- current end
		inc	eax		; EAX <- current end + 1
		cmp	eax,[esi+VMR_Start] ; does next region follow?
		jne	VirtMemMerge6	; regions are not continuous
		xchg	eax,edi		; EDI <- end of first region

; ------------- Cannot merge file mapped regions with different file mapping

		mov	eax,[ebx+VMR_File] ; first file
		cmp	eax,[esi+VMR_File] ; are files identical?
		jne	VirtMemMerge6	; cannot merge different files
		or	eax,eax		; is any file?
		jz	VirtMemMerge4	; it is not file mapped region
		xor	eax,eax		; EAX <- 0
		add	edi,[ebx+VMR_Offset] ; EDI <- new offset LOW
		adc	eax,[ebx+VMR_Offset+4] ; EAX <- new offset HIGH
		cmp	edi,[esi+VMR_Offset] ; check offset LOW
		jne	VirtMemMerge6	; regions cannot be merged
		cmp	eax,[esi+VMR_Offset+4] ; check offset HIGH
		jne	VirtMemMerge6	; regions cannot be merged

; ------------- Compare flags

VirtMemMerge4:	mov	eax,[ebx+VMR_Flags] ; EAX <- current flags
		cmp	eax,[esi+VMR_Flags] ; compare with next flags
		jne	VirtMemMerge6	; flags don't match

; ------------- Merge regions

		mov	eax,[esi+VMR_End] ; EAX <- end of next region
		mov	[ebx+VMR_End],eax ; set as end of current region

; ------------- Detach next region

		xchg	ebx,esi		; ESI <- current, EBX <- next
		call	RBTreeDelete	; detach next region

; ------------- Detach region from the shared list

		lea	eax,[ebx+VMR_Share] ; EAX <- share list
		call	ListDel		; detach region from the shared list

; ------------- Free next region

		xchg	eax,ebx		; EAX <- next region
		call	VirtMemRegFree	; free memoery region

; ------------- Get next region (here ESI = next region)

VirtMemMerge6:	dec	ecx		; counter of regions
		jz	VirtMemMerge8	; no other region
		mov	ebx,esi		; EBX <- current region
		call	RBTreeNext	; get next region
		xchg	ebx,esi		; ESI <- next region, EBX <- current
		jnc	VirtMemMerge2	; next region found OK

; ------------- Pop registers

VirtMemMerge8:	pop	edi		; pop EDI
		pop	esi		; pop ESI
		pop	ecx		; pop ECX
		pop	eax		; pop EAX
		ret

; -----------------------------------------------------------------------------
;                           Allocate virtual memory
; -----------------------------------------------------------------------------
; INPUT:	EAX = required starting address of the region
;			use:	0 = start of virtual space
;				VIRTMEM_MID = middle of virtual space
;				-1 or SYSTEM_ADDR = end of virtual space
;		EBX = flags
;			neither VMR_FINDUP nor VMR_FINDDOWN: exact address
;			VMR_FINDUP: search free space up
;			VMR_FINDDOWN: search free space down
;			VMR_FINDUP and VMR_FINDDOWN: nearest address up or down
;			VMR_OVERWRITE: can overwrite existing region
;					(only if exact address is required)
;		ECX = required size of the region
;		EDX = file descriptor (NULL=none)
;		EDI:ESI = offset in mapped file
; OUTPUT:	EAX = start address of the region
;		CY = error (EAX = 0)
; NOTES: Address will be rounded down to page size and size will be rounded up.
;	 If exact address is required then new region is big enough to hold
;	 both start and end address that was specified (i.e. EAX..EAX+ECX-1)
;	 even if they were rounded to page boundary.
; -----------------------------------------------------------------------------

; ------------- Push registers

VirtMemAlloc:	push	ebx		; push EBX
		push	ecx		; push ECX
		push	edx		; push EDX
		push	esi		; push ESI
		push	ebp		; push EBP
		mov	ebp,esp		; push ESP

; ------------- Local variables

		sub	esp,3*4
		mov	[ebp-1*4],edx	; file descriptor
		mov	[ebp-2*4],edi	; file offset HIGH
		mov	[ebp-3*4],esi	; file offset LOW

; ------------- Check size of the region

		cmp	ecx,SYSTEM_ADDR	; maximal size of region
		jae	near VirtMemAlloc9 ; invalid size of region (too big)
		or	ecx,ecx		; is region size valid?
		jz	near VirtMemAlloc9 ; invalid region size

; ------------- Limit starting address

		cmp	eax,SYSTEM_ADDR	; maximal address of region
		jb	VirtMemAlloc1	; address is OK
		mov	eax,SYSTEM_ADDR	; limit starting address

; ------------- Get virtual memory descriptor (-> EDX)

VirtMemAlloc1:	CURRENT	edx		; EDX <- get current task
		mov	esi,[edx+TASK_ResLim+RL_VirtMemReg] ; max. regions
		mov	edx,[edx+TASK_VirtMem] ; EDX<-virtual memory descriptor

; ------------- Check maximal number of regions

		cmp	[edx+RBR_Count],esi ; check regions
		jae	near VirtMemAlloc9 ; number of regions is exceeded

; ------------- Round address down to page boundary

		test	ebx,VMR_FINDUP|VMR_FINDDOWN ; exact address?		
		jnz	VirtMemAlloc2	; no exact address required
		mov	esi,eax		; ESI <- start address
		and	esi,(PAGE_SIZE-1) ; ESI = offset in a page
		add	ecx,esi		; ECX <- size correction
VirtMemAlloc2:	and	eax,PAGE_MASK	; round address to page boundary

; ------------- Round size up to page boundary

		add	ecx,PAGE_SIZE-1	; round up
		and	ecx,PAGE_MASK	; round size to page boundary

; ------------- Lock virtual memory descriptor

		pushf			; push flags
		cli			; disable interrupts
%ifdef	SMP
		LOCK_Lock (edx+VMD_Lock) ; lock virtual memory descriptor
%endif
; ------------- Free overwritten memory

		test	ebx,VMR_FINDUP|VMR_FINDDOWN ; exact address?		
		jnz	VirtMemAlloc4	; no exact address required
		test	ebx,VMR_OVERWRITE ; overwrite memory?
		jz	VirtMemAlloc3	; don't overwrite memory
		call	VirtMemFree	; unmap overwritten memory
		jmp	short VirtMemAlloc4

; ------------- Check overlapped region

VirtMemAlloc3:	call	VirtMemFindInt	; check overlapped region
                jnc	VirtMemAlloc8	; error, overlapped region found

; ------------- Get virtual memory region

VirtMemAlloc4:	call	VirtMemGetReg	; get virtual memory region
		jc	VirtMemAlloc8	; error

; ------------- Create new memory region

		mov	esi,ebx		; ESI <- flags
		xchg	eax,ebx		; push EAX
		call	VirtMemRegAlloc	; allocate virtual memory region
		xchg	eax,ebx		; pop EAX, EBX <- virtual memory region
		jc	VirtMemAlloc8	; memory error

; ------------- Fill up memory region entries

		push	eax		; push EAX
		mov	[ebx+VMR_Start],eax ; start address
		add	eax,ecx		; EAX <- end address+1
		dec	eax		; EAX <- end address
		mov	[ebx+VMR_End],eax ; end address
		mov	[ebx+VMR_Flags],esi ; flags
		mov	eax,[ebp-1*4]	; EAX <- file descriptor
		mov	[ebx+VMR_File],eax ; file descriptor
		mov	eax,[ebp-2*4]	; EAX <- file offset HIGH
		mov	[ebx+VMR_Offset+4],eax ; file offset HIGH
		mov	eax,[ebp-3*4]	; EAX <- file offset LOW
		mov	[ebx+VMR_Offset],eax ; file offset LOW
		lea	eax,[ebx+VMR_Share] ; EAX <- lsit of share regions
		LISTINIT eax		; initialize list of share regions
		pop	eax		; pop EAX

; ------------- Insert memory region into memory map (it must not overlap)

		call	VirtMemInsReg	; insert region into memory map

; ------------- Merge regions

		mov	ebx,eax		; EBX <- region
		call	VirtMemMerge	; merge regions

; ------------- OK: Unlock virtual memory descriptor
%ifdef	SMP
		LOCK_Unlock (edx+VMD_Lock) ; unlock virtual memory descriptor
%endif
		popf			; pop flags

; ------------- OK: Pop registers

		mov	esp,ebp		; pop ESP
		pop	ebp		; pop EBP
		pop	esi		; pop ESI
		pop	edx		; pop EDX
		pop	ecx		; pop ECX
		pop	ebx		; pop EBX
		clc			; clear error flag, operation OK
		ret

; ------------- ERROR: Unlock virtual memory descriptor

VirtMemAlloc8:
%ifdef	SMP
		LOCK_Unlock (edx+VMD_Lock) ; lock virtual memory descriptor
%endif
		popf			; pop flags

; ------------- ERROR: Pop registers

VirtMemAlloc9:	mov	esp,ebp		; pop ESP
		pop	ebp		; pop EBP
		pop	esi		; pop ESI
		pop	edx		; pop EDX
		pop	ecx		; pop ECX
		pop	ebx		; pop EBX

; ------------- Set error flag

		xor	eax,eax		; EAX <- 0, invalid address
		stc			; set error flag
		ret

; -----------------------------------------------------------------------------
;                      Set virtual memory protection flags
; -----------------------------------------------------------------------------
; INPUT:	EAX = required starting address of the region
;			use:	0 = start of virtual space
;				VIRTMEM_MID = middle of virtual space
;				-1 or SYSTEM_ADDR = end of virtual space
;		EBX = new flags
;		ECX = required size of the region
;		EDX = file descriptor (NULL=none)
;		EDI:ESI = offset in mapped file
; OUTPUT:	CY = error
; NOTES: Address will be rounded down to page size and size will be rounded up.
; -----------------------------------------------------------------------------

VirtMemProt:

; TODO !!!!!!!!!!!!!

		ret

; -----------------------------------------------------------------------------
;                       Allocate virtual memory region
; -----------------------------------------------------------------------------
; OUTPUT:	EAX = new virtual memory region (or EAX = NULL if CY)
;		CY = memory error (EAX = NULL)
; LOCKS:	BUFH_Lock, SysMemLock
; -----------------------------------------------------------------------------

VirtMemRegAlloc:push	edx		; push EDX
		mov	edx,VirtMemRegBuff ; EDX <- buffer of regions
		call	BuffAlloc	; allocate virtual memory region
		pop	edx		; pop EDX
		ret

; -----------------------------------------------------------------------------
;                          Free virtual memory region
; -----------------------------------------------------------------------------
; INPUT:	EAX = virtual memory region
; OUTPUT:	EAX = NULL
; LOCKS:	BUFH_Lock, SysMemLock
; -----------------------------------------------------------------------------

VirtMemRegFree:	push	edx		; push EDX
		mov	edx,VirtMemRegBuff ; EDX <- buffer of regions
		call	BuffFree	; free virtual memory region
		pop	edx		; pop EDX
		ret

; -----------------------------------------------------------------------------
;                             Expand stack
; -----------------------------------------------------------------------------
; INPUT:	EAX = address
;		EBX = memory region
; -----------------------------------------------------------------------------

ExpandStack:



; -----------------------------------------------------------------------------
;                                   Data
; -----------------------------------------------------------------------------

		DATA_SECTION

; ------------- Buffer of virtual memory regions (block 2 KB, aprox.30 entries)

		align	8, db 0
VirtMemRegBuff:	BUFFER	VMREG_size,800h

Back to source browser