0,0 → 1,469 |
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 ;copy address of page directory to safe place |
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 |
|
.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-0x807fffff to LFB |
mov eax,2 ;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 ecx,4096/4 ;number of pages in page table |
mov edi,[0xfe80] |
add edi,7 |
.loop3: |
;eax - linear address of page table |
;edi - current linear address with flags |
mov [eax],edi |
add eax,4 |
add edi,4096 |
loop .loop3 |
mov eax,[ebx+4] |
call MEM_Get_Linear_Address |
add dword [ebx+4],7 |
mov ecx,4096/4 |
.loop31: |
mov [eax],edi |
add eax,4 |
add edi,4096 |
loop .loop31 |
|
;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+APPDATA.dir_table],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+APPDATA.dir_table] |
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+APPDATA.dir_table] |
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+TASKDATA.state],9 ;if process running? |
jz .next ;skip empty slots |
shl ecx,3 |
cmp [second_base_address+0x80000+ecx+APPDATA.dir_table],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 |