mirror of
https://github.com/KolibriOS/kolibrios.git
synced 2024-12-24 07:36:48 +03:00
536 lines
14 KiB
NASM
536 lines
14 KiB
NASM
|
format ELF
|
||
|
section '.text' executable
|
||
|
public malloc
|
||
|
public free
|
||
|
public realloc
|
||
|
public mf_init
|
||
|
;multithread: ;uncomment this for thread-safe version
|
||
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||
|
;; Memory allocator for MenuetOS ;;
|
||
|
;; Halyavin Andrey halyavin@land.ru, 2006 ;;
|
||
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||
|
|
||
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||
|
;; allocated mem block structure ;;
|
||
|
;; +0: bit 0 - used flag ;;
|
||
|
;; bits 31..1 - block size ;;
|
||
|
;; +4: address of prev block ;;
|
||
|
;; +8 .. +(blocksize) - allocated memory ;;
|
||
|
;; +(blocksize) - next block ;;
|
||
|
;; ;;
|
||
|
;; free mem block structure ;;
|
||
|
;; +0: bit 0 - used flag ;;
|
||
|
;; bits 31..1 - block size ;;
|
||
|
;; +4: address of prev block ;;
|
||
|
;; +8: prev free block ;;
|
||
|
;; +12: next free block ;;
|
||
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||
|
memblock.size=0
|
||
|
memblock.prevblock=4
|
||
|
memblock.prevfreeblock=8
|
||
|
memblock.nextfreeblock=12
|
||
|
|
||
|
|
||
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||
|
;; mf_init ;;
|
||
|
;; Initialize memory map for dynamic use ;;
|
||
|
;; input: eax: starting address or 0 ;;
|
||
|
;; output: none ;;
|
||
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||
|
mf_init:
|
||
|
push ebx
|
||
|
push ecx
|
||
|
test eax,eax
|
||
|
jnz .noautodet
|
||
|
sub esp,1024
|
||
|
mov ebx,esp
|
||
|
mov ecx,-1
|
||
|
mov eax,9
|
||
|
int 0x40
|
||
|
mov eax,[esp+26]
|
||
|
add esp,1024
|
||
|
.noautodet:
|
||
|
add eax,15
|
||
|
and eax,not 15
|
||
|
mov [heapsmallblocks],eax
|
||
|
add eax,2048
|
||
|
mov [heapstart],eax
|
||
|
mov [heapfreelist],eax
|
||
|
mov [heaplastblock],eax
|
||
|
|
||
|
mov ecx,eax
|
||
|
if defined heapstartsize
|
||
|
add ecx,heapstartsize
|
||
|
else
|
||
|
add ecx,4096
|
||
|
end if
|
||
|
add ecx,4095
|
||
|
and ecx,not 4095
|
||
|
push eax
|
||
|
mov eax,64
|
||
|
mov ebx,1
|
||
|
int 0x40
|
||
|
pop eax
|
||
|
mov [eax+memblock.prevblock],dword 0
|
||
|
mov [heapend],ecx
|
||
|
mov [eax+memblock.size],ecx
|
||
|
sub [eax+memblock.size],eax
|
||
|
xor ebx,ebx
|
||
|
mov dword [eax+memblock.prevfreeblock],heapfreelist-memblock.nextfreeblock
|
||
|
mov [eax+memblock.nextfreeblock],ebx
|
||
|
mov [heapmutex],ebx
|
||
|
push edi
|
||
|
mov edi,[heapsmallblocks]
|
||
|
mov ecx,512
|
||
|
xor eax,eax
|
||
|
rep stosd
|
||
|
pop edi
|
||
|
pop ecx
|
||
|
pop ebx
|
||
|
ret
|
||
|
|
||
|
if defined multithread
|
||
|
heaplock:
|
||
|
push eax
|
||
|
push ebx
|
||
|
push ecx
|
||
|
mov eax,68
|
||
|
mov ebx,1
|
||
|
.loop:
|
||
|
xchg ecx,[heapmutex]
|
||
|
test ecx,ecx
|
||
|
jz .endloop
|
||
|
int 0x40 ;change task
|
||
|
jmp .loop
|
||
|
.endloop:
|
||
|
pop ecx
|
||
|
pop ebx
|
||
|
pop eax
|
||
|
ret
|
||
|
|
||
|
heapunlock:
|
||
|
mov [heapmutex],dword 0
|
||
|
ret
|
||
|
end if
|
||
|
|
||
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||
|
;; heap_split_block ;;
|
||
|
;; Split free block to allocated block and free one. ;;
|
||
|
;; input: ;;
|
||
|
;; eax - size of allocated block ;;
|
||
|
;; ebx - block ;;
|
||
|
;; output: ;;
|
||
|
;; eax - real size of allocated block ;;
|
||
|
;; ebx - pointer to new block ;;
|
||
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||
|
heap_split_block:
|
||
|
push ecx
|
||
|
mov ecx,[ebx+memblock.size]
|
||
|
sub ecx,16
|
||
|
cmp ecx,eax
|
||
|
jge .norm
|
||
|
inc dword [ebx+memblock.size]
|
||
|
mov eax,ecx
|
||
|
xor ebx,ebx
|
||
|
pop ecx
|
||
|
ret
|
||
|
.norm:
|
||
|
add ecx,16
|
||
|
mov [ebx+memblock.size],eax
|
||
|
inc dword [ebx+memblock.size]
|
||
|
mov [ebx+eax+memblock.prevblock],ebx
|
||
|
add ebx,eax
|
||
|
sub ecx,eax
|
||
|
mov [ebx+memblock.size],ecx
|
||
|
mov ecx,eax
|
||
|
mov eax,ebx
|
||
|
call heap_fix_right
|
||
|
mov eax,ecx
|
||
|
pop ecx
|
||
|
ret
|
||
|
|
||
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||
|
;; heap_add_free_block ;;
|
||
|
;; Add free block to one of free block lists. ;;
|
||
|
;; input: ;;
|
||
|
;; eax - address of free block ;;
|
||
|
;; output: ;;
|
||
|
;; none ;;
|
||
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||
|
heap_add_free_block:
|
||
|
cmp dword [eax+memblock.size],4096
|
||
|
push ebx
|
||
|
jge .bigblock
|
||
|
mov ebx,[eax+memblock.size]
|
||
|
shr ebx,1
|
||
|
add ebx,[heapsmallblocks]
|
||
|
push dword [ebx]
|
||
|
pop dword [eax+memblock.nextfreeblock]
|
||
|
mov [ebx],eax
|
||
|
mov dword [eax+memblock.prevfreeblock],ebx
|
||
|
sub dword [eax+memblock.prevfreeblock],memblock.nextfreeblock
|
||
|
mov ebx,[eax+memblock.nextfreeblock]
|
||
|
test ebx,ebx
|
||
|
jz .no_next_block
|
||
|
mov [ebx+memblock.prevfreeblock],eax
|
||
|
.no_next_block:
|
||
|
pop ebx
|
||
|
ret
|
||
|
.bigblock:
|
||
|
mov ebx,[heapfreelist]
|
||
|
mov [eax+memblock.nextfreeblock],ebx
|
||
|
mov [heapfreelist],eax
|
||
|
mov dword [eax+memblock.prevfreeblock],heapfreelist-memblock.nextfreeblock
|
||
|
; mov ebx,[eax+memblock.nextfreeblock]
|
||
|
test ebx,ebx
|
||
|
jz .no_next_big_block
|
||
|
mov [ebx+memblock.prevfreeblock],eax
|
||
|
.no_next_big_block:
|
||
|
pop ebx
|
||
|
ret
|
||
|
|
||
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||
|
;; heap_remove_block ;;
|
||
|
;; Remove free block from the list of free blocks. ;;
|
||
|
;; input: ;;
|
||
|
;; eax - free block ;;
|
||
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||
|
heap_remove_block:
|
||
|
push ebx
|
||
|
push ecx
|
||
|
mov ecx,[eax+memblock.prevfreeblock]
|
||
|
mov ebx,[eax+memblock.nextfreeblock]
|
||
|
mov [ecx+memblock.nextfreeblock],ebx
|
||
|
test ebx,ebx
|
||
|
jz .no_next_block
|
||
|
mov [ebx+memblock.prevfreeblock],ecx
|
||
|
.no_next_block:
|
||
|
pop ecx
|
||
|
pop ebx
|
||
|
ret
|
||
|
|
||
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||
|
;; mf_alloc
|
||
|
;; allocates a block of memory in heap
|
||
|
;; intput: eax: size of block
|
||
|
;; output: eax: address of allocated memory block or 0 if there's no mem.
|
||
|
;; allocator will not create new nodes that contain less that 8b of space,
|
||
|
;; and minimal allocation is actually 16 bytes - 8 for node and 8 for user.
|
||
|
;; allocator will never create non-aligned memory blocks.
|
||
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||
|
mf_alloc:
|
||
|
test eax,eax
|
||
|
jg .not_null ; test that we are not allocating null size block
|
||
|
xor eax,eax
|
||
|
ret
|
||
|
.not_null:
|
||
|
if defined multithread
|
||
|
call heaplock
|
||
|
end if
|
||
|
push edi
|
||
|
; push edx
|
||
|
push ecx
|
||
|
push ebx
|
||
|
add eax,7
|
||
|
and eax,not 7 ; make sure that block size is aligned
|
||
|
|
||
|
lea edi,[eax+8] ; desired block size
|
||
|
cmp edi,4096
|
||
|
jge .general_cycle
|
||
|
|
||
|
mov ebx,[heapsmallblocks]
|
||
|
xor ecx,ecx
|
||
|
shr edi,1
|
||
|
|
||
|
.smallloop:
|
||
|
cmp [ebx+edi],ecx
|
||
|
jnz .smallblockfound
|
||
|
add edi,4
|
||
|
cmp edi,2048
|
||
|
jl .smallloop
|
||
|
lea edi,[eax+8]
|
||
|
jmp .general_cycle
|
||
|
|
||
|
.smallblockfound:
|
||
|
lea ecx,[eax+8]
|
||
|
mov eax,[ebx+edi]
|
||
|
call heap_remove_block
|
||
|
mov ebx,eax
|
||
|
xchg eax,ecx
|
||
|
call heap_split_block
|
||
|
test ebx,ebx
|
||
|
jz .perfect_small_block
|
||
|
mov eax,ebx
|
||
|
call heap_add_free_block
|
||
|
.perfect_small_block:
|
||
|
lea eax,[ecx+8]
|
||
|
jmp .ret
|
||
|
|
||
|
.general_cycle:
|
||
|
;edi - size needed
|
||
|
mov eax,[heapfreelist]
|
||
|
|
||
|
.loop:
|
||
|
test eax,eax
|
||
|
jz .new_mem
|
||
|
cmp [eax+memblock.size],edi
|
||
|
jge .blockfound
|
||
|
mov eax,[eax+memblock.nextfreeblock]
|
||
|
jmp .loop
|
||
|
|
||
|
.blockfound:
|
||
|
call heap_remove_block
|
||
|
mov ebx,eax
|
||
|
mov ecx,eax
|
||
|
mov eax,edi
|
||
|
call heap_split_block
|
||
|
test ebx,ebx
|
||
|
jz .perfect_block
|
||
|
mov eax,ebx
|
||
|
call heap_add_free_block
|
||
|
.perfect_block:
|
||
|
lea eax,[ecx+8]
|
||
|
.ret:
|
||
|
if defined multithread
|
||
|
call heapunlock
|
||
|
end if
|
||
|
pop ebx
|
||
|
pop ecx
|
||
|
; pop edx
|
||
|
pop edi
|
||
|
ret
|
||
|
|
||
|
.new_mem:
|
||
|
mov eax,edi
|
||
|
add eax,4095
|
||
|
and eax,not 4095
|
||
|
mov ecx,[heapend]
|
||
|
add [heapend],eax
|
||
|
push eax
|
||
|
mov eax,64
|
||
|
push ebx
|
||
|
push ecx
|
||
|
mov ecx,[heapend]
|
||
|
mov ebx,1
|
||
|
int 0x40
|
||
|
pop ecx
|
||
|
pop ebx
|
||
|
pop eax
|
||
|
mov [ecx+memblock.size],eax
|
||
|
mov eax,[heaplastblock]
|
||
|
mov [ecx+memblock.prevblock],eax
|
||
|
mov [heaplastblock],ecx
|
||
|
mov eax,ecx
|
||
|
call heap_add_free_block
|
||
|
jmp .general_cycle
|
||
|
|
||
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||
|
;; heap_fix_right ;;
|
||
|
;; input: ;;
|
||
|
;; eax - pointer to free block ;;
|
||
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||
|
heap_fix_right:
|
||
|
push ebx
|
||
|
mov ebx,eax
|
||
|
add ebx,[eax+memblock.size]
|
||
|
cmp ebx,[heapend]
|
||
|
jz .endblock
|
||
|
mov [ebx+memblock.prevblock],eax
|
||
|
pop ebx
|
||
|
ret
|
||
|
.endblock:
|
||
|
mov [heaplastblock],eax
|
||
|
pop ebx
|
||
|
ret
|
||
|
|
||
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||
|
;; heap_merge_left ;;
|
||
|
;; input: ;;
|
||
|
;; eax - pointer to free block ;;
|
||
|
;; output: ;;
|
||
|
;; eax - pointer to merged block ;;
|
||
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||
|
heap_merge_left:
|
||
|
push ebx
|
||
|
mov ebx,[eax+memblock.prevblock]
|
||
|
test ebx,ebx
|
||
|
jz .ret
|
||
|
test byte [ebx+memblock.size],1
|
||
|
jnz .ret
|
||
|
xchg eax,ebx
|
||
|
call heap_remove_block
|
||
|
mov ebx,[ebx+memblock.size]
|
||
|
add [eax+memblock.size],ebx
|
||
|
call heap_fix_right
|
||
|
.ret:
|
||
|
pop ebx
|
||
|
ret
|
||
|
|
||
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||
|
;; heap_merge_right ;;
|
||
|
;; input: ;;
|
||
|
;; eax - pointer to free block ;;
|
||
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||
|
heap_merge_right:
|
||
|
push ebx
|
||
|
mov ebx,eax
|
||
|
add ebx,[eax+memblock.size]
|
||
|
cmp ebx,[heapend]
|
||
|
jz .ret
|
||
|
test byte [ebx+memblock.size],1
|
||
|
jnz .ret
|
||
|
xchg eax,ebx
|
||
|
call heap_remove_block
|
||
|
xchg eax,ebx
|
||
|
mov ebx,[ebx+memblock.size]
|
||
|
add [eax+memblock.size],ebx
|
||
|
call heap_fix_right
|
||
|
.ret:
|
||
|
pop ebx
|
||
|
ret
|
||
|
|
||
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||
|
;; mf_free ;;
|
||
|
;; input: ;;
|
||
|
;; eax - pointer ;;
|
||
|
;; output: ;;
|
||
|
;; eax=1 - ok ;;
|
||
|
;; eax=0 - failed ;;
|
||
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||
|
mf_free:
|
||
|
test eax,eax
|
||
|
jnz .no_null
|
||
|
inc eax
|
||
|
ret
|
||
|
.no_null:
|
||
|
if defined multithread
|
||
|
call heaplock
|
||
|
end if
|
||
|
sub eax,8
|
||
|
dec dword [eax+memblock.size]
|
||
|
call heap_merge_left
|
||
|
call heap_merge_right
|
||
|
call heap_add_free_block
|
||
|
.ret:
|
||
|
if defined multithread
|
||
|
call heapunlock
|
||
|
end if
|
||
|
ret
|
||
|
|
||
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||
|
;; heap_try_reloc
|
||
|
;; input:
|
||
|
;; eax - address
|
||
|
;; ebx - new size
|
||
|
;; output:
|
||
|
;; ebx=1 - ok
|
||
|
;; ebx=0 - failed
|
||
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||
|
heap_try_reloc:
|
||
|
push eax
|
||
|
sub eax,8
|
||
|
add ebx,15
|
||
|
dec dword [eax+memblock.size]
|
||
|
and ebx,not 7
|
||
|
cmp [eax+memblock.size],ebx
|
||
|
jge .truncate
|
||
|
push ebx
|
||
|
mov ebx,eax
|
||
|
add ebx,[eax+memblock.size]
|
||
|
cmp ebx,[heapend]
|
||
|
jz .fail ;todo: we can allocate new mem here
|
||
|
test [ebx+memblock.size],byte 1
|
||
|
jnz .fail
|
||
|
xchg eax,ebx
|
||
|
call heap_remove_block
|
||
|
mov eax,[eax+memblock.size]
|
||
|
add [ebx+memblock.size],eax
|
||
|
mov eax,ebx
|
||
|
call heap_fix_right
|
||
|
pop ebx
|
||
|
.truncate:
|
||
|
xchg eax,ebx
|
||
|
call heap_split_block
|
||
|
test ebx,ebx
|
||
|
jz .no_last_block
|
||
|
mov eax,ebx
|
||
|
call heap_add_free_block
|
||
|
call heap_merge_right
|
||
|
.no_last_block:
|
||
|
xor ebx,ebx
|
||
|
pop eax
|
||
|
inc ebx
|
||
|
ret
|
||
|
.fail:
|
||
|
pop ebx
|
||
|
xor ebx,ebx
|
||
|
pop eax
|
||
|
inc dword [eax-8+memblock.size]
|
||
|
ret
|
||
|
|
||
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||
|
;; mf_realloc
|
||
|
;; input:
|
||
|
;; eax - pointer
|
||
|
;; ebx - new size
|
||
|
;; output:
|
||
|
;; eax - new pointer
|
||
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||
|
mf_realloc:
|
||
|
push ebx
|
||
|
if defined multithread
|
||
|
call heaplock
|
||
|
end if
|
||
|
call heap_try_reloc
|
||
|
test ebx,ebx
|
||
|
jnz .ret
|
||
|
;allocate new memory
|
||
|
push eax
|
||
|
mov eax,[esp+4]
|
||
|
call mf_alloc
|
||
|
test eax,eax
|
||
|
jz .fail
|
||
|
push esi
|
||
|
push edi
|
||
|
push ecx
|
||
|
mov edi,eax
|
||
|
mov esi,[esp+12]
|
||
|
mov ecx,[esi-8+memblock.size]
|
||
|
shr ecx,2
|
||
|
rep movsd
|
||
|
pop ecx
|
||
|
pop edi
|
||
|
pop esi
|
||
|
xchg eax,[esp]
|
||
|
call mf_free
|
||
|
.fail:
|
||
|
pop eax
|
||
|
.ret:
|
||
|
if defined multithread
|
||
|
call heapunlock
|
||
|
end if
|
||
|
pop ebx
|
||
|
ret
|
||
|
;C entries
|
||
|
malloc:
|
||
|
mov eax,[esp+4]
|
||
|
call mf_alloc
|
||
|
ret
|
||
|
free:
|
||
|
mov eax,[esp+4]
|
||
|
call mf_free
|
||
|
ret
|
||
|
realloc:
|
||
|
mov edx,ebx
|
||
|
mov eax,[esp+4]
|
||
|
mov ebx,[esp+8]
|
||
|
call mf_realloc
|
||
|
mov ebx,edx
|
||
|
ret
|
||
|
section '.bss' writeable
|
||
|
heapsmallblocks rd 1
|
||
|
heapstart rd 1
|
||
|
heapend rd 1
|
||
|
heapfreelist rd 1
|
||
|
heapmutex rd 1
|
||
|
heaplastblock rd 1
|