; =============================================================================
;
; 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
|