if ~defined memmanager_inc memmanager_inc_fix: memmanager_inc fix memmanager_inc_fix ;for testing in applications if defined B32 iskernel=1 else iskernel=0 end if ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; Memory allocator for MenuetOS kernel ;; Andrey Halyavin, halyavin@land.ru 2005 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; heap block structure - ;; you can handle several ranges of ;; pages simultaneosly. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; .heap_linear_address equ 0 .heap_block_size equ 4 .heap_physical_address equ 8 .heap_reserved equ 12 .heap_block_info equ 16 max_heaps equ 8 .range_info equ 36 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; memory manager data ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; MEM_heap_block_ rd .heap_block_info*max_heaps/4 MEM_heap_block=MEM_heap_block_+second_base_address MEM_heap_count_ rd 1 MEM_heap_count=MEM_heap_count_+second_base_address if iskernel = 0 MEM_general_mutex rd 1 MEM_call_count rd 1 MEM_mutex_pid rd 1 MEM_mutex_count rd 1 else MEM_cli_count_ rd 1 MEM_cli_count=MEM_cli_count_+second_base_address MEM_cli_prev_ rd 1 MEM_cli_prev=MEM_cli_prev_+second_base_address end if ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;MEM_Init ;;Initialize memory manager structures. ;;Must be called first. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; MEM_Init: push eax xor eax,eax if iskernel = 0 mov [MEM_heap_count],eax mov [MEM_general_mutex],eax mov [MEM_call_count],eax mov [MEM_mutex_pid],eax mov [MEM_mutex_count],eax else mov [MEM_cli_prev],eax ;init value = 0 dec eax mov [MEM_cli_count],eax ;init value = -1 end if pop eax ret ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;change_task ;;procedure for changing tasks. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; if iskernel = 0 change_task: push eax push ebx mov eax,5 xor ebx,ebx inc ebx int 0x40 pop ebx pop eax ret end if ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;MEM_get_pid ;;determine current pid ;;result: ;; eax - pid ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; if iskernel = 0 MEM_get_pid: push ebx push ecx sub esp,1024 mov eax,9 mov ebx,esp mov ecx,-1 int 0x40 mov eax,[esp+30] add esp,1024 pop ecx pop ebx ret else ; pid_address dd 0x3000 ;MEM_get_pid: ; mov eax,[pid_address] ; mov eax,[eax] ; ret end if ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;MEM_Heap_Lock ;;Wait until all operations with heap will be finished. ;;Between MEM_Heap_Lock and MEM_Heap_UnLock operations ;;with heap are forbidden. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; MEM_Heap_Lock: if iskernel = 0 push eax inc dword [MEM_call_count] MEM_Heap_Lock_wait: mov eax,1 xchg [MEM_general_mutex],eax test eax,eax jz MEM_Heap_Lock_end call MEM_get_pid cmp [MEM_mutex_pid],eax jz MEM_Heap_Lock_end1 call change_task jmp MEM_Heap_Lock_wait MEM_Heap_Lock_end1: inc dword [MEM_mutex_count] pop eax ret MEM_Heap_Lock_end: call MEM_get_pid mov [MEM_mutex_pid],eax mov dword [MEM_mutex_count],1 pop eax ret else pushfd cli inc dword [MEM_cli_count] jz MEM_Heap_First_Lock add esp,4 ret MEM_Heap_First_Lock: ;save interrupt flag shr dword [esp],9 and dword [esp],1 pop dword [MEM_cli_prev] ret end if ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;MEM_Heap_UnLock ;;After this routine operations with heap are allowed. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; MEM_Heap_UnLock: if iskernel = 0 push eax xor eax,eax dec dword [MEM_mutex_count] jnz MEM_Heap_UnLock_No_Wait1 dec dword [MEM_call_count] mov [MEM_mutex_pid],eax mov [MEM_general_mutex],eax;release mutex BEFORE task switching jz MEM_Heap_UnLock_No_Wait call change_task ;someone want to use heap - switch tasks MEM_Heap_UnLock_No_Wait: pop eax ret MEM_Heap_UnLock_No_Wait1: dec dword [MEM_call_count] jz MEM_Heap_UnLock_No_Wait2 call change_task MEM_Heap_UnLock_No_Wait2: pop eax ret else dec dword [MEM_cli_count] js MEM_Heap_UnLock_last ret MEM_Heap_UnLock_last: cmp dword [MEM_cli_prev],0 ;restore saved interrupt flag jz MEM_Heap_UnLock_No_sti sti MEM_Heap_UnLock_No_sti: ret end if ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;MEM_Add_Heap ;;Add new range to memory manager. ;;eax - linear address ;;ebx - size in pages ;;ecx - physical address ;;Result: ;; eax=1 - success ;; eax=0 - failed ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; MEM_Add_Heap: push edx call MEM_Heap_Lock mov edx,[MEM_heap_count] cmp edx,max_heaps jz MEM_Add_Heap_Error inc dword [MEM_heap_count] shl edx,4 mov [MEM_heap_block+edx+.heap_linear_address],eax mov [MEM_heap_block+edx+.heap_block_size],ebx shl dword [MEM_heap_block+edx+.heap_block_size],12 mov [MEM_heap_block+edx+.heap_physical_address],ecx lea edx,[4*ebx+.range_info+4095] ;calculate space for page info table and edx,0xFFFFF000 mov [eax],eax add [eax],edx ;first 4 bytes - pointer to first free page ;clean page info area push edi lea edi,[eax+4] mov ecx,edx shr ecx,2 push eax xor eax,eax rep stosd pop eax pop edi ;create free pages list. mov ecx,[eax] shl ebx,12 add eax,ebx ;eax - address after block MEM_Add_Heap_loop: add ecx,4096 mov [ecx-4096],ecx ;set forward pointer cmp ecx,eax jnz MEM_Add_Heap_loop mov dword [ecx-4096],0 ;set end of list MEM_Add_Heap_ret: call MEM_Heap_UnLock pop edx ret MEM_Add_Heap_Error: xor eax,eax jmp MEM_Add_Heap_ret ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;MEM_Get_Physical_Address ;;Translate linear address to physical address ;;Parameters: ;; eax - linear address ;;Result: ;; eax - physical address ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; if used MEM_Get_Physical_Address MEM_Get_Physical_Address: push ecx call MEM_Heap_Lock mov ecx,[MEM_heap_count] dec ecx shl ecx,4 MEM_Get_Physical_Address_loop: sub eax,[MEM_heap_block+ecx+.heap_linear_address] jl MEM_Get_Physical_Address_next cmp eax,[MEM_heap_block+ecx+.heap_block_size] jge MEM_Get_Physical_Address_next add eax,[MEM_heap_block+ecx+.heap_physical_address] jmp MEM_Get_Physical_Address_loopend MEM_Get_Physical_Address_next: add eax,[MEM_heap_block+ecx+.heap_linear_address] sub ecx,16 jns MEM_Get_Physical_Address_loop xor eax,eax ;address not found MEM_Get_Physical_Address_loopend: call MEM_Heap_UnLock pop ecx ret end if ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;MEM_Get_Linear_Address ;;Translate physical address to linear address. ;;Parameters: ;; eax - physical address ;;Result: ;; eax - linear address ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; if used MEM_Get_Linear_Address MEM_Get_Linear_Address: push ecx call MEM_Heap_Lock mov ecx,[MEM_heap_count] dec ecx shl ecx,4 MEM_Get_Linear_Address_loop: sub eax,[MEM_heap_block+ecx+.heap_physical_address] jl MEM_Get_Linear_Address_Next cmp eax,[MEM_heap_block+ecx+.heap_block_size] jge MEM_Get_Linear_Address_Next add eax,[MEM_heap_block+ecx+.heap_linear_address] call MEM_Heap_UnLock pop ecx ret MEM_Get_Linear_Address_Next: add eax,[MEM_heap_block+ecx+.heap_physical_address] sub ecx,16 jns MEM_Get_Linear_Address_loop call MEM_Heap_UnLock pop ecx xor eax,eax ;address not found ret end if ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;MEM_Alloc_Page ;;Allocate and add reference to page ;;Result: ;; eax<>0 - physical address of page ;; eax=0 - not enough memory ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; if used MEM_Alloc_Page MEM_Alloc_Page: push ecx call MEM_Heap_Lock mov ecx,[MEM_heap_count] dec ecx shl ecx,4 MEM_Alloc_Page_loop: push ecx mov ecx,[MEM_heap_block+ecx+.heap_linear_address] cmp dword [ecx],0 jz MEM_Alloc_Page_loopend mov eax,[ecx] push dword [eax] pop dword [ecx] sub eax,ecx push eax shr eax,10 mov word [ecx+.range_info+eax],1 pop eax pop ecx add eax,[MEM_heap_block+ecx+.heap_physical_address] jmp MEM_Alloc_Page_ret MEM_Alloc_Page_loopend: pop ecx sub ecx,16 jns MEM_Alloc_Page_loop xor eax,eax MEM_Alloc_Page_ret: call MEM_Heap_UnLock pop ecx ret end if ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;MEM_Alloc_Page_Linear ;;Allocate and add reference to page ;;Result: ;; eax<>0 - linear address of page ;; eax=0 - not enough memory ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; if used MEM_Alloc_Page_Linear MEM_Alloc_Page_Linear: push ecx call MEM_Heap_Lock mov ecx,[MEM_heap_count] dec ecx shl ecx,4 MEM_Alloc_Page_Linear_loop: push ecx mov ecx,[MEM_heap_block+ecx+.heap_linear_address] cmp dword [ecx],0 jz MEM_Alloc_Page_Linear_loopend mov eax,[ecx] push dword [eax] pop dword [ecx] push eax sub eax,ecx shr eax,10 mov word [ecx+.range_info+eax],1 pop eax pop ecx jmp MEM_Alloc_Page_Linear_ret MEM_Alloc_Page_Linear_loopend: pop ecx sub ecx,16 jns MEM_Alloc_Page_Linear_loop xor eax,eax MEM_Alloc_Page_Linear_ret: call MEM_Heap_UnLock pop ecx ret end if ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;MEM_Free_Page ;;Remove reference and free page if number of ;;references is equal to 0 ;;Parameters: ;; eax - physical address of page ;;Result: ;; eax - 1 success ;; eax - 0 failed ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; if used MEM_Free_Page MEM_Free_Page: test eax,eax jz MEM_Free_Page_Zero test eax,0xFFF jnz MEM_Free_Page_Not_Aligned push ebx push ecx push edx call MEM_Heap_Lock mov ecx,[MEM_heap_count] dec ecx shl ecx,4 MEM_Free_Page_Heap_loop: sub eax,[MEM_heap_block+ecx+.heap_physical_address] js MEM_Free_Page_Heap_loopnext cmp eax,[MEM_heap_block+ecx+.heap_block_size] jl MEM_Free_Page_Heap_loopend MEM_Free_Page_Heap_loopnext: add eax,[MEM_heap_block+ecx+.heap_physical_address] sub ecx,16 jns MEM_Free_Page_Heap_loop xor eax,eax inc eax jmp MEM_Free_Page_ret MEM_Free_Page_Heap_loopend: mov ecx,[MEM_heap_block+ecx+.heap_linear_address] mov ebx,eax add eax,ecx shr ebx,10 mov edx,[ecx+.range_info+ebx] test edx,0x80000000 jnz MEM_Free_Page_Bucket test dx,dx jz MEM_Free_Page_Error dec word [ecx+.range_info+ebx] jnz MEM_Free_Page_OK MEM_Free_Page_Bucket: push dword [ecx] mov [ecx],eax pop dword [eax] mov dword [ecx+.range_info+ebx],0 MEM_Free_Page_OK: mov eax,1 MEM_Free_Page_ret: call MEM_Heap_UnLock pop edx pop ecx pop ebx ret MEM_Free_Page_Error: xor eax,eax jmp MEM_Free_Page_ret MEM_Free_Page_Zero: inc eax ret MEM_Free_Page_Not_Aligned: xor eax,eax ret end if ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;MEM_Free_Page_Linear ;;Remove reference and free page if number of ;;references is equal to 0 ;;Parameters: ;; eax - linear address of page ;;Result: ;; eax - 1 success ;; eax - 0 failed ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; if used MEM_Free_Page_Linear MEM_Free_Page_Linear: test eax,eax jz MEM_Free_Page_Linear_Zero test eax,0xFFF jnz MEM_Free_Page_Linear_Not_Aligned push ebx push ecx push edx call MEM_Heap_Lock mov ecx,[MEM_heap_count] dec ecx shl ecx,4 MEM_Free_Page_Linear_Heap_loop: sub eax,[MEM_heap_block+ecx+.heap_linear_address] js MEM_Free_Page_Linear_Heap_loopnext cmp eax,[MEM_heap_block+ecx+.heap_block_size] jl MEM_Free_Page_Linear_Heap_loopend MEM_Free_Page_Linear_Heap_loopnext: add eax,[MEM_heap_block+ecx+.heap_linear_address] sub ecx,16 jns MEM_Free_Page_Linear_Heap_loop xor eax,eax inc eax jmp MEM_Free_Page_Linear_ret MEM_Free_Page_Linear_Heap_loopend: mov ecx,[MEM_heap_block+ecx+.heap_linear_address] mov ebx,eax add eax,ecx shr ebx,10 mov edx,[ecx+.range_info+ebx] test edx,0x80000000 jnz MEM_Free_Page_Linear_Bucket test dx,dx jz MEM_Free_Page_Linear_Error dec word [ecx+.range_info+ebx] jnz MEM_Free_Page_Linear_OK MEM_Free_Page_Linear_Bucket: mov edx,[ecx] mov [eax],edx mov dword [eax+4],0 mov [ecx],eax test edx,edx jz MEM_Free_Page_No_Next mov [edx+4],eax MEM_Free_Page_No_Next: mov dword [ecx+.range_info+ebx],0 MEM_Free_Page_Linear_OK: xor eax, eax inc eax MEM_Free_Page_Linear_ret: call MEM_Heap_UnLock pop edx pop ecx pop ebx ret MEM_Free_Page_Linear_Error: xor eax,eax jmp MEM_Free_Page_Linear_ret MEM_Free_Page_Linear_Zero: inc eax ret MEM_Free_Page_Linear_Not_Aligned: xor eax,eax ret end if ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;MEM_Alloc_Pages ;;Allocates set of pages. ;;Parameters: ;; eax - number of pages ;; ebx - buffer for physical addresses ;;Result: ;; eax - number of allocated pages ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; if used MEM_Alloc_Pages MEM_Alloc_Pages: push eax push ebx push ecx mov ecx,eax test ecx,ecx jz MEM_Alloc_Pages_ret MEM_Alloc_Pages_loop: call MEM_Alloc_Page test eax,eax jz MEM_Alloc_Pages_ret mov [ebx],eax add ebx,4 dec ecx jnz MEM_Alloc_Pages_loop MEM_Alloc_Pages_ret: sub [esp+8],ecx pop ecx pop ebx pop eax ret end if ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;MEM_Alloc_Pages_Linear ;;Allocates set of pages. ;;Parameters: ;; eax - number of pages ;; ebx - buffer for linear addresses ;;Result: ;; eax - number of allocated pages ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; if used MEM_Alloc_Pages_Linear MEM_Alloc_Pages_Linear: push eax push ebx push ecx mov ecx,eax test ecx,ecx jz MEM_Alloc_Pages_Linear_ret MEM_Alloc_Pages_Linear_loop: call MEM_Alloc_Page_Linear test eax,eax jz MEM_Alloc_Pages_Linear_ret mov [ebx],eax add ebx,4 dec ecx jnz MEM_Alloc_Pages_Linear_loop MEM_Alloc_Pages_Linear_ret: sub [esp+8],ecx pop ecx pop ebx pop eax ret end if ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;MEM_Free_Pages ;;Parameters: ;; eax - number of pages ;; ebx - array of addresses ;;Result: ;; eax=1 - succcess ;; eax=0 - failed ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; if used MEM_Free_Pages MEM_Free_Pages: push ebx push ecx mov ecx,eax test ecx,ecx jz MEM_Free_Pages_ret MEM_Free_Pages_loop: mov eax,[ebx] call MEM_Free_Page add ebx,4 test eax,eax jz MEM_Free_Pages_ret dec ecx jnz MEM_Free_Pages_loop MEM_Free_Pages_ret: pop ecx pop ebx ret end if ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;MEM_Free_Pages_Linear ;;Parameters: ;; eax - number of pages ;; ebx - array of addresses ;;Result: ;; eax=1 - succcess ;; eax=0 - failed ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; if used MEM_Free_Pages_Linear MEM_Free_Pages_Linear: push ebx push ecx mov ecx,eax test ecx,ecx jz MEM_Free_Pages_Linear_ret MEM_Free_Pages_Linear_loop: mov eax,[ebx] call MEM_Free_Page_Linear add ebx,4 test eax,eax jz MEM_Free_Pages_Linear_ret dec ecx jnz MEM_Free_Pages_Linear_loop MEM_Free_Pages_Linear_ret: pop ecx pop ebx ret end if ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;MEM_Get_Heap_Number ;;Calculate number of heap which pointer belongs to. ;;Parameter: ;; eax - address ;;Result: ;; ecx - number of heap*16. ;; eax=0 if address not found. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; if used MEM_Get_Heap_Number MEM_Get_Heap_Number: call MEM_Heap_Lock mov ecx,[MEM_heap_count] dec ecx shl ecx,4 MEM_Get_Heap_loop: sub eax,[MEM_heap_block+ecx+.heap_physical_address] jl MEM_Get_Heap_loopnext cmp eax,[MEM_heap_block+ecx+.heap_block_size] jl MEM_Get_Heap_loopend MEM_Get_Heap_loopnext: add eax,[MEM_heap_block+ecx+.heap_physical_address] sub ecx,16 jns MEM_Get_Heap_loop call MEM_Heap_UnLock xor eax,eax ret MEM_Get_Heap_loopend: add eax,[MEM_heap_block+ecx+.heap_physical_address] call MEM_Heap_UnLock ret end if ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;MEM_Get_Heap_Number_Linear ;;Calculate number of heap which pointer belongs to. ;;Parameter: ;; eax - address ;;Result: ;; ecx - number of heap*16. ;; eax=0 if address not found. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; if used MEM_Get_Heap_Number_Linear MEM_Get_Heap_Number_Linear: call MEM_Heap_Lock mov ecx,[MEM_heap_count] dec ecx shl ecx,4 MEM_Get_Heap_Linear_loop: sub eax,[MEM_heap_block+ecx+.heap_linear_address] jl MEM_Get_Heap_Linear_loopnext cmp eax,[MEM_heap_block+ecx+.heap_block_size] jl MEM_Get_Heap_Linear_loopend MEM_Get_Heap_Linear_loopnext: add eax,[MEM_heap_block+ecx+.heap_linear_address] sub ecx,16 jns MEM_Get_Heap_Linear_loop call MEM_Heap_UnLock xor eax,eax ret MEM_Get_Heap_Linear_loopend: add eax,[MEM_heap_block+ecx+.heap_linear_address] call MEM_Heap_UnLock ret end if ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;MEM_Alloc ;;Allocate small region. ;;Parameters: ;; eax - size (0