📄 init.asm
字号:
; get the address of KData
mov eax, OFFSET32 _KData
call PaFromVa
; (eax) = PA of KData
mov dword ptr [eax+OFFSET_MEM_FOR_PT], SYSTEM_PAGES; MemForPT = memeory used for system pages
mov dword ptr [eax+OFFSET_CPU_CAP], edi ; save CPU capability bits
; setup esp to use KStack (physical here)
mov esp, eax
sub esp, 4 ; esp = &KData - 4 == &KSTack
; save the VA of OEMAddressTable onto stack
mov eax, esi
call VaFromPa ; (eax) = VA of OEMAddressTable upon return
mov dword ptr [esp], eax ; save address of OEMAddressTable on stack
; NOTE: since push is pre-decrement, the conent
; won't be over-written by "push" operation
; Figure out pTOC->ulRamFree
mov eax, OFFSET32 _pTOC ; (eax) = VA of &pTOC
call PaFromVa ; (eax) = PA of &pTOC
mov eax, dword ptr [eax] ; (eax) = VA of pTOC
call PaFromVa ; (eax) = PA of pTOC
mov eax, dword ptr [eax+OFFSET_ULRAMFREE] ; (eax) = VA free RAM
push eax ; save the VA of Page Directory onto stack
call PaFromVa ; (eax) = PA of free RAM
; (eax) = PA of the beginning of the free RAM
; 1st pages of Free RAM is going to be used as Page Directory
mov ebx, eax ; (ebx) = PA of Page Directory
mov edx, edi ; (edx) = cpu capability bits
; clear the system pages
cld
mov ecx, ZERO_BLOCK_SIZE / 4
mov edi, ebx
xor eax, eax
rep stosd
; (edx) = CPU capaibility
test edx, CPUID_PSE
jnz short Use4MPage
;
; no 4M page support, use 4k pages
;
; calculate size for Page Tables
mov ecx, esi ; (ecx) = OEMPageTable
xor edi, edi ; size init to 0
cntNext:
add edi, [ecx+8] ; (edi) = accumulated size
; round up to multiple of 4M
add edi, 0003fffffh ; round up to multiple of 4M
and edi, 0ffc00000h ;
add ecx, 12 ; (ecx) = next OEMPageTable Entry
cmp dword ptr [ecx], 0
jne short cntNext
; (edi) = total memory sizes
shr edi, 9 ; (edi) = size of page tables
; = (size / 4M) * 2 * PAGE_SIZE
; update KData.nMemForPT
mov eax, OFFSET32 _KData ; (eax) = VA of KData
call PaFromVa
add dword ptr [eax+OFFSET_MEM_FOR_PT], edi ; update KData.nMemForPT
mov edx, ebx ; (edx) = PA of free RAM
add edx, SYSTEM_PAGES ; skip the system pages
mov eax, esi ; (eax) = OEMPageTable
NextTable4K:
Call FillPD4K ; fill the page talbe for one entry
mov ecx, dword ptr [eax+8] ; (ecx) = size of the entry
shr ecx, 9 ; (ecx) = size of page tables for this entry
; = (size / 4M) * 2 * PAGE_SIZE
add edx, ecx ; (edx) = next page table entry
add eax, 12 ; (eax) = next OEMPageTableEntry
cmp dword ptr [eax], 0
jne short NextTable4K
jmp short DoneSettingPD
Use4MPage:
;
; with 4M page support, use 4M page
; (edx) = CPU capability bits
; figure out PDE bits
mov eax, edx ; (eax) = cpu capability bits
mov edx, PDE_PS ; (edx) = support 4M page bit for PDE
test eax, CPUID_PGE ; support global page?
jz short SetupPDE4M
or edx, PDE_G
SetupPDE4M:
; setup page directory
mov eax, esi
NextTable4M:
Call FillPD4M
add eax, 12 ; (eax) = next OEMPageTableEntry
cmp dword ptr [eax], 0
jne short NextTable4M
.586p
CR4_PSE EQU 010H
CR4_PGE EQU 080H
mov ecx, CR4_PSE ; 4M page enabled
test edx, PDE_G ; support global page?
jz short SetupCr4
; yes, support Global Page
or ecx, CR4_PGE
SetupCr4:
; update CR4
mov eax, cr4
or eax, ecx
mov cr4, eax
.486p
DoneSettingPD:
cld
; Setup value in Syscall page
mov edi, ebx ;
add edi, SYSPAGE_SYSCALL ; (edi) = PA of Syscall page
mov eax, 20cd20cdh ; (eax) = int 0x20 x 2
mov ecx, 1024 ; fill syscall page with int 0x20 instructions
rep stosd
; Setup value in SyscallDir
mov edi, ebx ;
add edi, SYSPAGE_SYSCALLDIR ; (edi) = PA of Syscall page directory
mov edx, edi ; (edx) = PA of Syscall page directory
mov eax, ebx
add eax, SYSPAGE_SYSCALL+PAGE_ATTRIB_RO_USER ; (eax) = Page directory entry of Syscall page directory
mov ecx, 1024 ; every entry in SyscallDir point to to same Page (syscall page)
rep stosd
; setup page directory for syscall dir
add edx, PAGE_ATTRIB_RO_USER ; (edx) = page directory entry for syscall directory
mov DWORD PTR [ebx][0FFCh], edx ; setup global page directory
;
; Create the identity-mapped addresses (physical = linear), because
; Pentium-II requires that once paging is enabled, the next instruction
; must come from the same address as if paging wasn't enabled.
;
; First, the mapping for the eip register.
;
mov eax, OFFSET32 PagingEnabled
call PaFromVa
mov edi, eax ; (edi) = PA of PageEnabled
; Next, the mapping for the gdt.
sub esp, 8
sgdt [esp]
mov eax, dword ptr 2[esp]
add esp, 8
; (eax) = PA of gdtBase ; save PA of gdtbase
push eax
;
; the value for gdtBase is 0xffffffff!!!!
; not a physical address at all
;
;call VaFromPa ; (eax) = VA of gdtbase
sub eax, LIN_TO_PHYS_OFFSET
mov ecx, OFFSET32 PagingEnabled ; (ecx) = VA of PageEnabled
mov edx, edi ; (edx) = PA of PageEnabled
pop edi ; (edi) = PA of gdtbase
;
; !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
; !!! from here on, esi no longer points to OEMAddressTable
; !!! ANY CALL after this TO PaFromVa / VaFromPa will FAIL
; !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
;
mov esi, eax ; (esi) = VA of gdtbase
;
; ECX = current linear addr, EDX = current physical addr.
;
shr ecx, 22 ; Which 4MB?
shl ecx, 2 ; DWORD index
shr edx, 22 ; Which 4MB?
shl edx, 2 ; DWORD index
;
; ESI = linear gdtbase, EDI = physical gdtbase.
;
shr esi, 22 ; Which 4MB?
shl esi, 2 ; DWORD index
shr edi, 22 ; Which 4MB?
shl edi, 2 ; DWORD index
;
; Save off the original page directory entry for the physical address.
;
push DWORD PTR [ebx][edx]
push DWORD PTR [ebx][edi]
;
; Copy the page directory entry for the current linear
; address to the physical address.
;
mov eax, DWORD PTR [ebx][ecx]
and eax, not PDE_G ; only works if PDE_G implies PDE_PS
mov DWORD PTR [ebx][edx], eax
mov eax, DWORD PTR [ebx][esi]
and eax, not PDE_G ; only works if PDE_G implies PDE_PS
mov DWORD PTR [ebx][edi], eax
;
; Get the saved values off the stack.
;
mov cr3, ebx
pop ebx ; Original pde value for gdtbase
pop ebp ; Original pde value for PagingEnabled
;
; We are now identity-mapped, okay to enable paging.
;
mov esi, OFFSET32 PagingEnabled
mov eax, cr0
or eax, PG_MASK OR WP_MASK ; enable paging & write-protection for Ring0
and eax, not 060000000h ; clear cache disable & cache write-thru bits
align 16
mov cr0, eax
jmp esi
align 4
PagingEnabled:
wbinvd ; clear out the cache
;
; Switch to virtual addressing for the stack and save of all these registers.
;
mov esp, OFFSET32 _KStack
mov eax, dword ptr [esp] ; retrieve VA of OEMAddressTable
mov ecx, dword ptr [esp-4] ; retrieve VA of Page Directory
push edx ; eip pde index
push ebp ; eip pde value
push edi ; gdt pde index
push ebx ; gdt pde value
push 0
popfd
mov ebx, ecx ; (ebx) = VA of Page Directory
push ebx ; arg1 - VA of PageDir
push eax ; arg0 - VA of OEMAddressTable
call _SystemInitialization ; Load new gdtr, among other things.
add sp, 8 ; pop the arguments
;
; Restore the original page directory entry for the physical addresses.
; We cannot restore these PDEs until _SystemInitialization has reloaded
; gdtr.
;
pop eax ; gdt pde value
pop edx ; gdt pde index
mov DWORD PTR [ebx][edx], eax ; Restore GDT phys addr mapping
pop eax ; PagingEnabled pde value
pop edx ; PagingEnalbled pde index
mov DWORD PTR [ebx][edx], eax ; Restore PaginEnabled phys addr mapping
;
; Flush the tlb, since we are unmapping.
;
mov eax, cr3 ; Flush the TLB
mov cr3, eax
call _SafeIdentifyCpu
call _KernelInit
xor edi, edi
jmp _Reschedule
_KernelInitialize ENDP
;-------------------------------------------------------------------------------
;-------------------------------------------------------------------------------
_INTERRUPTS_ON proc NEAR PUBLIC
sti
ret
_INTERRUPTS_ON endp
;-------------------------------------------------------------------------------
;-------------------------------------------------------------------------------
_INTERRUPTS_OFF proc NEAR PUBLIC
cli
ret
_INTERRUPTS_OFF endp
;-------------------------------------------------------------------------------
; INTERRUPTS_ENABLE - enable/disable interrupts based on arguemnt and return current status
;-------------------------------------------------------------------------------
_INTERRUPTS_ENABLE proc NEAR PUBLIC
mov ecx, [esp+4] ; (ecx) = argument
pushfd
pop eax ; (eax) = current flags
shr eax, EFLAGS_IF_BIT ;
and eax, 1 ; (eax) = 0 if interrupt was disabled, 1 if enabled
test ecx, ecx ; enable or disable?
jne short _INTERRUPTS_ON
; disable interrupt
cli
ret
_INTERRUPTS_ENABLE endp
_TEXT ENDS
END
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -