if ~defined mem_inc mem_inc_fix: mem_inc fix mem_inc_fix ;include "memmanag.inc" ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;High-level memory management in MenuetOS. ;;It uses memory manager in memmanager.inc ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; second_base_address=0xC0000000 std_application_base_address=0x10000000 general_page_table_ dd 0 general_page_table=general_page_table_+second_base_address ;----------------------------------------------------------------------------- create_general_page_table: ;input ; none ;output ; none ;Procedure create general page directory and write ;it address to [general_page_table]. pushad mov eax,1 ;alloc 1 page mov ebx,general_page_table ;write address to [general_page_table] call MEM_Alloc_Pages ;allocate page directory mov eax,[general_page_table] call MEM_Get_Linear_Address ;eax - linear address of page directory mov edi,eax mov ebx,eax xor eax,eax mov ecx,4096/4 cld rep stosd ;clear page directory mov eax,4 mov edx,eax call MEM_Alloc_Pages ;alloc page tables for 0x0-0x1000000 region cmp eax,edx jnz $ ;hang if not enough memory ;fill page tables xor esi,esi mov ebp,7 .loop: ;esi - number of page in page directory ;ebp - current page address ;ebx - linear address of page directory mov eax,[ebx+4*esi] add dword [ebx+4*esi],7 ;add flags to address of page table call MEM_Get_Linear_Address ;eax - linear address of page table mov ecx,4096/4 ;ecx (counter) - number of pages in page table ;current address=4Mb*esi cmp esi,2 jz .start_lfb_map ;lfb map begin at 0x800000 cmp esi,3 jz .end_lfb_map ;lfb map end at 0xC00000 jmp .loop1 .start_lfb_map: ;current address=lfb address mov ebp,[0x2f0000+0x9018] add ebp,7 ;add flags jmp .loop1 .end_lfb_map: ;current address=linear address mov ebp,12*0x100000+7 .loop1: mov [eax],ebp ;write page address (with flags) in page table add eax,4 add ebp,4096 ;size of page=4096 bytes loop .loop1 inc esi ;next page directory entry cmp esi,edx jnz .loop ;map region 0x80000000-0x803fffff to 0x800000-0xcfffff mov eax,1 ;size of the region is 4Mb so only 1 page table needed mov edx,ebx ;ebx still contains linear address of the page directory add ebx,0x800 call MEM_Alloc_Pages ;alloc page table for the region mov eax,[ebx] add dword [ebx],7 ;add flags call MEM_Get_Linear_Address ;get linear address of the page table mov ebx,eax mov ecx,4096/4 ;number of pages in page table mov eax,8*0x100000+7 .loop3: ;ebx - linear address of page table ;eax - current linear address with flags mov [ebx],eax add ebx,4 add eax,4096 loop .loop3 ;map region 0xC0000000-* to 0x0-* mov esi,edx ;esi=linear address of the page directory lea edi,[esi+(second_base_address shr 20)];add offset of entry (0xC00) mov ecx,4 rep movsd ;first 16Mb of the region mapped as 0x0-0x1000000 block mov eax,[0xfe8c] ;eax=memory size add eax,0x3fffff shr eax,22 mov esi,eax ;calculate number of entries in page directory sub esi,4 ;subtract entries for first 16Mb. mov ebp,0x1000000+7 ;start physical address with flags ;mapping memory higher than 16Mb .loop4: ;esi (counter) - number of entries in page directory ;edi - address of entry test esi,esi jle .loop4end call MEM_Alloc_Page ;alloc page table for entry in page directory mov [edi],eax add dword [edi],7 ;write physical address of page table in page directory add edi,4 ;move entry pointer call MEM_Get_Linear_Address mov ecx,eax xor edx,edx .loop5: ;ecx - linear address of page table ;edx - index of page in page table ;ebp - current mapped physical address with flags mov [ecx+4*edx],ebp ;write address of page in page table add ebp,0x1000 ;move to next page inc edx cmp edx,4096/4 jl .loop5 dec esi jmp .loop4 .loop4end: .set_cr3: ;set value of cr3 register to the address of page directory mov eax,[general_page_table] add eax,8+16 ;add flags mov cr3,eax ;now we have full access paging popad ret ;----------------------------------------------------------------------------- simple_clone_cr3_table: ;Parameters: ; eax - physical address of cr3 table (page directory) ;result: ; eax - physical address of clone of cr3 table. ;Function copy only page directory. push ecx push edx push esi push edi call MEM_Get_Linear_Address ;eax - linear address of cr3 table mov esi,eax call MEM_Alloc_Page test eax,eax jz .failed ;eax - physical address of new page diretory mov edx,eax call MEM_Get_Linear_Address mov edi,eax mov ecx,4096/4 cld ;esi - address of old page directory ;edi - address of new page directory rep movsd ;copy page directory mov eax,edx .failed: pop edi pop esi pop edx pop ecx ret ;----------------------------------------------------------------------------- create_app_cr3_table: ;Parameters: ; eax - slot of process (index in 0x3000 table) ;result: ; eax - physical address of table. ;This function create page directory for new process and ;write it physical address to offset 0xB8 of extended ;process information. push ebx mov ebx,eax mov eax,[general_page_table] call simple_clone_cr3_table ;clone general page table shl ebx,8 mov [second_base_address+0x80000+ebx+0xB8],eax ;save address of page directory pop ebx ret ;----------------------------------------------------------------------------- get_cr3_table: ;Input: ; eax - slot of process ;result: ; eax - physical address of page directory shl eax,8 ;size of process extended information=256 bytes mov eax,[second_base_address+0x80000+eax+0xB8] ret ;----------------------------------------------------------------------------- dispose_app_cr3_table: ;Input: ; eax - slot of process ;result: ; none ;This procedure frees page directory, ;page tables and all memory of process. pushad mov ebp,eax ;ebp = process slot in the procedure. shl eax,8 mov eax,[second_base_address+0x80000+eax+0xB8] mov ebx,eax ;ebx = physical address of page directory call MEM_Get_Linear_Address mov edi,eax ;edi = linear address of page directory mov eax,[edi+(std_application_base_address shr 20)] and eax,not (4096-1) call MEM_Get_Linear_Address mov esi,eax ;esi = linear address of first page table ;search threads ; mov ecx,0x200 xor edx,edx mov eax,0x2 .loop: ;eax = current slot of process mov ecx,eax shl ecx,5 cmp byte [second_base_address+0x3000+ecx+0xa],9 ;if process running? jz .next ;skip empty slots shl ecx,3 cmp [second_base_address+0x80000+ecx+0xB8],ebx ;compare page directory addresses jnz .next inc edx ;thread found .next: inc eax cmp eax,[0x3004] ;exit loop if we look through all processes jle .loop ;edx = number of threads ;our process is zombi so it isn't counted cmp edx,1 jg .threadsexists ;if there isn't threads then clear memory. add edi,std_application_base_address shr 20 .loop1: ;edi = linear address of current directory entry ;esi = linear address of current page table test esi,esi jz .loop1end xor ecx,ecx .loop2: ;ecx = index of page mov eax,[esi+4*ecx] test eax,eax jz .loopend ;skip empty entries and eax,not (4096-1) ;clear flags push ecx call MEM_Free_Page ;free page pop ecx .loopend: inc ecx cmp ecx,1024 ;there are 1024 pages in page table jl .loop2 mov eax,esi call MEM_Free_Page_Linear ;free page table .loop1end: add edi,4 ;move to next directory entry mov eax,[edi] and eax,not (4096-1) call MEM_Get_Linear_Address mov esi,eax ;calculate linear address of new page table test edi,0x800 jz .loop1 ;test if we at 0x80000000 address? and edi,not (4096-1) ;clear offset of page directory entry mov eax,edi call MEM_Free_Page_Linear ;free page directory popad ret .threadsexists: ;do nothing popad ;last thread will free memory ret ;----------------------------------------------------------------------------- mem_alloc_specified_region: ;eax - linear directory address ;ebx - start address (aligned to 4096 bytes) ;ecx - size in pages ;result: ; eax=1 - ok ; eax=0 - failed ;Try to alloc and map ecx pages to [ebx;ebx+4096*ecx) interval. pushad mov ebp,ebx ;save start address for recoil mov esi,eax .gen_loop: ;esi = linear directory address ;ebx = current address ;ecx = remaining size in pages mov edx,ebx shr edx,22 mov edi,[esi+4*edx] ;find directory entry for current address test edi,edi jnz .table_exists ;check if page table allocated call MEM_Alloc_Page ;alloc page table test eax,eax jz .failed mov [esi+4*edx],eax add dword [esi+4*edx],7 ;write it address with flags call MEM_Get_Linear_Address call mem_fill_page ;clear page table jmp .table_linear .table_exists: ;calculate linear address of page table mov eax,edi and eax,not (4096-1) ;clear flags call MEM_Get_Linear_Address .table_linear: ;eax = linear address of page table mov edx,ebx shr edx,12 and edx,(1024-1) ;calculate index in page table mov edi,eax .loop: ;edi = linear address of page table ;edx = current page table index ;ecx = remaining size in pages ;ebx = current address test ecx,ecx jle .endloop1 ;all requested pages allocated call MEM_Alloc_Page ;alloc new page test eax,eax jz .failed mov [edi+4*edx],eax add dword [edi+4*edx],7 ;write it address with flags call MEM_Get_Linear_Address call mem_fill_page ;clear new page ;go to next page table entry dec ecx add ebx,4096 inc edx test edx,(1024-1) jnz .loop jmp .gen_loop .endloop1: popad mov eax,1 ;ok ret .failed: ;calculate data for recoil sub ebx,ebp shr ebx,12 mov ecx,ebx ;calculate number of allocated pages mov eax,esi ;restore linear address of page directory mov ebx,ebp ;restore initial address call mem_free_specified_region ;free all allocated pages popad xor eax,eax ;fail ret ;----------------------------------------------------------------------------- mem_fill_page: ;Input: ; eax - address ;result: ; none ;set to zero 4096 bytes at eax address. push ecx push edi mov edi,eax mov ecx,4096/4 xor eax,eax rep stosd lea eax,[edi-4096] pop edi pop ecx ret ;----------------------------------------------------------------------------- mem_free_specified_region: ;eax - linear page directory address ;ebx - start address (aligned to 4096 bytes) ;ecx - size in pages ;result - none ;Free pages in [ebx;ebx+4096*ecx) region. pushad mov esi,eax xor ebp,ebp .gen_loop: ;esi = linear page directory address ;ebx = current address ;ecx = remaining pages ;ebp = 0 for first page table ; 1 otherwise mov edx,ebx shr edx,22 mov eax,[esi+4*edx] ;find directory entry for current address and eax,not (4096-1) test eax,eax jnz .table_exists ;skip absent page tables mov edx,ebx shr edx,12 and edx,(1024-1) ;edx - index of current page add ebx,1 shl 22 add ecx,edx and ebx,not ((1 shl 22)-1) mov ebp,1 ;set flag sub ecx,1024 ;ecx=ecx-(1024-edx) jg .gen_loop popad ret .table_exists: call MEM_Get_Linear_Address ;eax - linear address of table mov edx,ebx shr edx,12 and edx,(1024-1) ;edx - index of current page mov edi,eax .loop: ;edi = linear address of page table entry ;edx = index of page table entry ;ecx = remaining pages test ecx,ecx jle .endloop1 mov eax,[edi+4*edx] and eax,not (4096-1) call MEM_Free_Page ;free page mov dword [edi+4*edx],0 ;and clear page table entry dec ecx inc edx cmp edx,1024 jl .loop test ebp,ebp jz .first_page mov eax,edi call MEM_Free_Page_Linear ;free page table mov edx,ebx shr edx,22 mov dword [esi+4*edx],0 ;and clear page directory entry .first_page: add ebx,1 shl 22 and ebx,not ((1 shl 22)-1) ;calculate new current address mov ebp,1 ;set flag jmp .gen_loop .endloop1: popad ret end if