- 论坛徽章:
- 0
|
19、 地址空间规划的实现
源代码如下:
------------------------------------------------------------------------------------
bits 32
PG_P equ 0x01
PG_W equ 0x02
PG_USER equ 0x04
PG_PWT equ 0x08
PG_PCD equ 0x10
PG_PS equ 0x80
;---------------------------------
; get_kernel_map_base(mem_size)
; return: kernel_map_base
;---------------------------------
get_kernel_maped_base:
mov eax, [esp+4] ; mem size
dec eax
shr eax, 1
add eax, 0x00000FFF ; (4*1024)-1
and eax, 0xFFFFF000 ; ~(4*1024-1)
ret 4
; ----------------------------------
; get_PML4E_index(va_hi32, va_low32)
;
; input: virtual address
; out: PML4E index
; ----------------------------------
get_PML4E_index:
mov eax, [esp+4] ; VA high32
and eax, 0x0000ff80
shr eax, 7
ret 8
; ----------------------------------
; get_PDPE_index(va_hi32, va_low32)
;
; input: virtual address
; out: PDPE index
; ----------------------------------
get_PDPE_index:
push ebp
mov eax, [esp+8] ; VA high32
mov ebp, [esp+12] ; VA low32
and eax, 0x0000007f
shl eax, 2
shr ebp, 30
add eax, ebp
pop ebp
ret 8
; ----------------------------------
; get_PDE_index(va_hi32, va_low32)
;
; input: virtual address
; out: PDE index
; ----------------------------------
get_PDE_index:
mov eax, [esp+8] ; VA low32
and eax, 0x3fe00000
shr eax, 21
ret 8
; ----------------------------------
; get_PTE_index(va_hi32, va_low32)
;
; input: virtual address
; out: PTE index
; ----------------------------------
get_PTE_index:
mov eax, [esp+8] ; VA low32
and eax, 0x001ff000
shr eax, 12
ret 8
; ---------------------------------------------------------------------
; int do_init_page_table(pa_address, va_hi32, va_low32, size, is_2M_page)
;
; input: pa_addess ----- physical address
; virtual_address --- virtual address
; size: xK size
; is_2M_page: 1-2M_page 0-4K_page
; output: -1: failure
; 0: successed
;-------------------------------------------------------------------
do_init_page_table:
jmp do_init_page_table_main
segment_number dd 0 ; 0-segment --- PDPT0
dd 1 ; 1-segment --- PDPT1
dd 0 ; 2-segment --- reserved
dd 0 ; 3-segment --- reserved
dd 0 ; 4-segment --- reserved
dd 0 ; 5-segment --- reserved
dd 2 ; 6-segment --- PDPT2
dd 3 ; 7-segment --- PDPT3
dd 4 ; 8-segment --- PDPT4
dd 0 ; 9-segment --- reserved
dd 0 ; A-segment --- reserved
dd 5 ; B-segment --- PDPT5
dd 0 ; C-segment --- reserved
dd 0 ; D-segment --- reserved
dd 0 ; E-segment --- reserved
dd 6 ; F-segment --- PDPT5
do_init_page_table_main:
mov edi, [esp+4] ; 32-bit physical address
mov esi, [esp+8] ; 64 bit virtual address high 32
mov ebx, [esp+12] ; 64-bit virtual address low 32
mov eax, [mem_total]
push eax
call get_kernel_maped_base ; eax <---- kernel_maped_base
mov ebp, eax
push ebp ; save kernel_maped_base
; -------------------------------
; set PML4T entry
; -------------------------------
push ebx
push esi
call get_PML4E_index
push eax
shr eax, 5
mov eax, [segment_number + eax *4] ; get segment number
push eax ; save segment number
shl eax, 12 ; eax = eax * 4K
mov edx, [ebp + PDPT_BASE_OFFSET] ; edx <--- PDPT_BASE
lea edx, [edx + eax] ; edx <--- PDPTx_BASE
mov ecx, [ebp + PML4T_BASE_OFFSET]
pop ebp ; ebp <--- segment number
pop eax ; PML4E index
mov dword [ecx + eax * 8], edx ; PML4T[PML4E] <--- PDPTx_BASE
mov dword [ecx + eax * 8 + 4], 0
cmp eax, 0x100 ; 8-segment ???
jae do_init_supervisor_page
or dword [ecx + eax * 8], PG_P | PG_W | PG_USER
do_init_supervisor_page:
or dword [ecx + eax * 8], PG_P | PG_W
;-----------------------------------------------------
; now: edx = PDPTx_base ebp = segment number
; eax = PML4E ecx = PML4T_BASE
;
; [esp] = kernel_maped_base
;-----------------------------------------------------
mov ecx, ebp ; ecx = segment number
pop ebp
push ecx ; save segment number
; ---------------------------------------------------
; set PDPT entry
; ---------------------------------------------------
push ebx ; low32
push esi ; hi32
call get_PDPE_index
push eax
shl ecx, (PDPT_ENTRIES/2) ; segment_number * PDPT_ENTRIES (segment_number * 4)
shl ecx, 12 ;segment_number * PDPT_ENTRIES * 4K (segment_number * 4 * 4K)
shl eax, 12 ; eax = PDPE_index * 4K
lea ecx, [ecx + eax] ; ecx = PDT_BASE-offset
mov eax, [ebp + PDT_BASE_OFFSET] ; eax = PDT_BASE
lea ecx, [eax + ecx] ; PDTx_BASE
pop eax
mov [edx + eax * 8], ecx ; PDPT[PDPE] = PDTx_BASE
mov dword [edx + eax * 8 + 4], 0
or dword [edx + eax * 8], PG_P | PG_W | PG_USER
;-----------------------------------------------------------
; Now: eax = PDPE_index ecx = PDTx_BASE
; edx = PDPTx_base ebp = kernel_maped_base
;
; [esp] = segment number
;-----------------------------------------------------------
pop edx ; edx = segment_number
;----------------------------------------------------------
; set PDT entry
;----------------------------------------------------------
shl eax, 21 ; PDPE_index * 2M
shl edx, 23 ; segment_number * 8M
add edx, eax ; (segment_number * 8M) + (PDPE_index * 2M)
push ebx
push esi
call get_PDE_index
push eax ; save PDE_index
shl eax, 12 ; PDE * 4K
add edx, eax ; PTx_BASE offset (segment * 8M + PDPE * 2M + PDE * 4K)
mov eax, [ebp + PT_BASE_OFFSET] ; edx = PT_BASE
lea edx, [eax + edx] ; edx = PTx_BASE
pop eax ; eax = PDE
push ebp ; save kernel_maped_base
push edx ; save PTx_BASE
mov ebp, [esp + 28] ; is_2M_page
mov edx, [esp + 24] ; size
test ebp, ebp
jz set_PDT_entry_4K
pop ebp
pop ebp
set_PDT_entry_2M_loop:
and edi, 0xffe00000 ; get 2M-page
mov dword [ecx + eax * 8], edi
mov dword [ecx + eax * 8 + 4], 0
or dword [ecx + eax * 8], PG_PS | PG_P | PG_W | PG_USER
sub edx, 2*1024*1024 ; 2M
jle do_init_page_table_succeed
inc eax
add edi, 2*1024*1024
jmp set_PDT_entry_2M_loop
set_PDT_entry_4K:
mov ebp, [esp] ; ebp <--- PTx_BASE
set_PDT_entry_4K_loop:
mov [ecx + eax * 8], ebp ; PDT[PDE] <--- PTx_BASE
mov dword [ecx + eax * 8 + 4], 0
or dword [ecx + eax * 8], PG_P | PG_W | PG_USER
sub edx, 2*1024*1024
jle set_PDT_entry_4K_next
inc eax
add ebp, 4*1024 ; next PT
jmp set_PDT_entry_4K_loop
set_PDT_entry_4K_next:
pop edx
pop ebp
;-----------------------------------------------------------
; Now: eax = PDE_index ecx = PDTx_BASE
; edx = PTx_base ebp = kernel_maped_base
;
; [esp] = segment_number
;-----------------------------------------------------------
;***********************************************
; set PT entry
;***********************************************
push ebx
push esi
call get_PTE_index
mov ecx, [esp + 16] ; size
mov ebp, [esp + 20] ; is_2M_page
test ebp, ebp
jnz do_init_page_table_failure
set_PT_entry_loop:
and edi, 0xfffff000 ; physical address
mov dword [edx + eax * 8], edi ; PTE <----- page
mov dword [edx + eax * 8 + 4], 0
or dword [edx + eax * 8], PG_P | PG_W | PG_USER
sub ecx, 4*1024
jle do_init_page_table_succeed
inc eax
add edi, 4*1024
jmp set_PT_entry_loop
do_init_page_table_succeed:
xor eax, eax
jmp do_init_page_table_done
do_init_page_table_failure:
mov eax, -1
do_init_page_table_done:
ret 20
;---------------------------------
;
; int init_page_struct(void)
;---------------------------------
init_page_struct:
mov eax, dword [mem_total]
mov ebx, eax
push eax
call get_kernel_maped_base
test eax, eax ; eax <--- kernel_maped_base
jz init_page_struct_failure
cmp eax, KERNEL_EREA_SIZE
jl init_page_struct_failure
mov dword [eax + KERNEL_MAPED_BASE_OFFSET], eax ; [KERNEL_MAPED_BASE] <-- kernel_maped_base
mov dword [eax + MEMORY_SIZE_OFFSET], ebx ; [MEMORY_SIZE_BASE] <--- memory_size
lea ebx, [eax + SYSTEM_DATA_SIZE]
mov dword [eax + PML4T_BASE_OFFSET], ebx ; [PML4T_BASE] <--- pml4t_base
lea ebx, [ebx + PML4T_SIZE]
mov dword [eax + PDPT_BASE_OFFSET], ebx ; [PDPT_BASE] <--- pdpt_base
lea ebx, [ebx + PDPT_SIZE]
mov dword [eax + PDT_BASE_OFFSET], ebx ; [PDT_BASE] <--- pdt_base
lea ebx, [ebx + PDT_SIZE]
mov dword [eax + PT_BASE_OFFSET], ebx ; [PT_BASE] <--- pt_base
lea ebx, [ebx + PT_SIZE]
add ebx, 0x0FFFFF
and ebx, 0xFFF00000
mov dword [eax + KERNEL_CODE_BASE_OFFSET], ebx ; [KERNEL_CODE_BASE] <--- kernel_code_base
add ebx, KERNEL_CODE_SIZE + 1*1024*1024
mov dword [eax + B_SEGMENT_BASE_OFFSET], ebx ; [B_SEGMENT_BASE] <---- b_segment_base
add ebx, RESERVED_SIZE + 1024*1024
mov dword [eax + KERNEL_STACK_BASE_OFFSET], ebx ; [KERNEL_STACK_BASE] <---- kernel_stack_base
add ebx, KERNEL_STACK_SIZE + 1024*1024
mov dword [eax + KERNEL_HEAP_BASE_OFFSET], ebx ; [KERNEL_HEAP_BASE] <--- kernel_heap_base
xor ebx, ebx
mov dword [eax + DOS_BASE_OFFSET], ebx ; [DOS_BASE] <--- 0
add ebx, DOS_SIZE + 1024*1024
;**** [COMPATIBILITY_CODE_BASE] <--- compatibility_code_base
mov dword [eax + COMPATIBILITY_CODE_BASE_OFFSET], ebx
add ebx, COMPATIBILITY_CODE_SIZE + 1024*1024
mov dword [eax + USER_CODE_BASE_OFFSET], ebx ; [USER_CODE_BASE] <--- user_code_base
add ebx, USER_CODE_SIZE + 1024*1024
mov dword [eax + SHARED_LIB_BASE_OFFSET], ebx ; [SHARED_LIB_BASE] <--- shared lib base
add ebx, SHARED_LIB_SIZE + 1024*1024
mov dword [eax + USER_STACK_BASE_OFFSET], ebx ; [USER_STACK_BASE] <--- user stack base
add ebx, USER_STACK_SIZE + 1024*1024
mov dword [eax + USER_HEAP_BASE_OFFSET], ebx ; [USER_HEAP_BASE] <---- user heap base
push eax ; save kernel_maped_base
; -------------------- system data struct area map -------------------------
;
; the system data struct area: 0xffff8000_00000000 ~ 0xffff8000_039fffff (58M)
; --------------------------------------------------------------------------
push dword 0 ; 2M_page ? 0-4K_page, 1-2M_page
push SYSTEM_DATA_SIZE + PAGE_STRUCT_SIZE ; 58M
push dword 0 ; low32
push dword 0xffff8000 ; high32
push eax ; kernel_maped_base
call do_init_page_table
test eax, eax
jnz init_page_struct_failure
;--------------- kernel code area map ------------------------------
;
; the kernel code area: 0xFFFF8000_40000000 ~ 0xFFFF8000_403FFFFF (4M)
;-------------------------------------------------------------------
mov eax, [esp]
mov eax, [eax + KERNEL_CODE_BASE_OFFSET]
push dword 1 ; 4M-page
push dword KERNEL_CODE_SIZE
push dword 0x40000000
push dword 0xffff8000
push eax
call do_init_page_table
test eax, eax
jnz init_page_struct_failure
;--------------- B-segment area map ------------------------------
;
; B-segment area: 0xFFFFB000_00000000 ~ 0xFFFFB000_00000FFF (4K)
;-------------------------------------------------------------------
mov eax, [esp]
mov eax, [eax + B_SEGMENT_BASE_OFFSET]
push dword 0 ; 4K-page
push dword RESERVED_SIZE
push dword 0x00000000
push dword 0xffffB000
push eax
call do_init_page_table
test eax, eax
jnz init_page_struct_failure
;--------------- kernel stack area map ------------------------------
;
; the kernel stack area: 0xFFFFF000_FFFE0000 ~ 0xFFFFF000_FFFEFFFF (64K)
;-------------------------------------------------------------------
mov eax, [esp]
mov eax, [eax + KERNEL_STACK_BASE_OFFSET]
push dword 0 ; 4K-page
push dword KERNEL_STACK_SIZE
push dword 0xfffe0000
push dword 0xfffff000
push eax
call do_init_page_table
test eax, eax
jnz init_page_struct_failure
;------------------------ kernel heap area map -------------------------------
;
; the kernel heap area: 0xFFFFF000_00000000 ~ 0xFFFFF000_000FFFFF (1M)
;-----------------------------------------------------------------------------
mov eax, [esp]
mov eax, [eax + KERNEL_HEAP_BASE_OFFSET]
push dword 0 ; 4K-page
push dword KERNEL_HEAP_SIZE
push dword 0x00000000
push dword 0xfffff000
push eax
call do_init_page_table
test eax, eax
jnz init_page_struct_failure
;--------------- legacy DOS area map ------------------------------
;
; the legacy DOS area: 0x00000000_00000000 ~ 0x00000000_000FFFFF (1M)
;-------------------------------------------------------------------
mov eax, [esp]
mov eax, [eax + DOS_BASE_OFFSET]
push dword 0 ; 4K-page
push dword DOS_SIZE
push dword 0x00000000
push dword 0x00000000
push eax
call do_init_page_table
test eax, eax
jnz init_page_struct_failure
;--------------- compatibility code area map ------------------------------
;
; the ccompatibility code area: 0x00000000_40000000 ~ 0x00000000_401FFFFF (1M)
;-------------------------------------------------------------------
mov eax, [esp]
mov eax, [eax + COMPATIBILITY_CODE_BASE_OFFSET]
push dword 0 ; 4K-page
push dword COMPATIBILITY_CODE_SIZE
push dword 0x40000000
push dword 0x00000000
push eax
call do_init_page_table
test eax, eax
jnz init_page_struct_failure
;--------------- user code area map ------------------------------
;
; the user code area: 0x00001000_40000000 ~ 0x00001000_403FFFFF (4M)
;-------------------------------------------------------------------
mov eax, [esp]
mov eax, [eax + USER_CODE_BASE_OFFSET]
push dword 0 ; 4K-page
push dword USER_CODE_SIZE
push dword 0x40000000
push dword 0x00001000
push eax
call do_init_page_table
test eax, eax
jnz init_page_struct_failure
;--------------- shared lib area map ------------------------------
;
; the shared lib area: 0x00006000_00000000 ~ 0x00006000_001FFFFF (2M)
;-------------------------------------------------------------------
mov eax, [esp]
mov eax, [eax + SHARED_LIB_BASE_OFFSET]
push dword 0 ; 4K-page
push dword SHARED_LIB_SIZE
push dword 0x00000000
push dword 0x00006000
push eax
call do_init_page_table
test eax, eax
jnz init_page_struct_failure
;--------------- user stack area map ------------------------------
;
; the user stack area: 0x00007000_C0000000 ~ 0x00007000_C07FFFFF (8M)
;-------------------------------------------------------------------
mov eax, [esp]
mov eax, [eax + USER_STACK_BASE_OFFSET]
push dword 0 ; 4K-page
push dword USER_STACK_SIZE
push dword 0xC0000000
push dword 0x00007000
push eax
call do_init_page_table
test eax, eax
jnz init_page_struct_failure
;--------------- user heap area map ------------------------------
;
; the user stack area: 0x00007000_80000000 ~ 0x00007000_83FFFFFF (64M)
;-------------------------------------------------------------------
pop eax
mov eax, [eax + USER_HEAP_BASE_OFFSET]
push dword 0 ; 4K-page
push dword USER_HEAP_SIZE
push dword 0x80000000
push dword 0x00007000
push eax
call do_init_page_table
test eax, eax
jnz init_page_struct_failure
xor eax, eax
init_page_struct_failure:
mov eax, -1
init_page_struct_done:
ret
改天有时间再讲解。 |
|