kolibrios-fun/programs/develop/metcc/trunk/libc/mem/memalloc.asm
Andrey Halyavin (halyavin) 51d395d0cc initial import of metcc project
git-svn-id: svn://kolibrios.org@145 a494cfbc-eb01-0410-851d-a64ba20cac60
2006-09-07 14:14:53 +00:00

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