📄 startup.asm
字号:
;
; Copyright (c) Microsoft Corporation. All rights reserved.
;
;
; Use of this source code is subject to the terms of the Microsoft end-user
; license agreement (EULA) under which you licensed this SOFTWARE PRODUCT.
; If you did not accept the terms of the EULA, you are not authorized to use
; this source code. For a copy of the EULA, please see the LICENSE.RTF on your
; install media.
;
;-------------------------------------------------------------------------------
;
; THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF
; ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO
; THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A
; PARTICULAR PURPOSE.
;
;-------------------------------------------------------------------------------
.486p
PAGE_SIZE EQU 1000h
PAGE_ATTRIB_RW EQU 000001100011b
PAGE_ATTRIB_RW_NOCACHE EQU 000001111011b
PAGE_ATTRIB_RO_USER EQU 000000100101b
PAGE_ATTRIB_RW_USER EQU 000001100111b
PageRange MACRO Start, NumPages, Attrib
LOCAL CurPhys
.ERRNZ Start AND (PAGE_SIZE-1)
CurPhys = Start
REPEAT NumPages
dd CurPhys OR Attrib
CurPhys = CurPhys + PAGE_SIZE
ENDM
ENDM
LIN_TO_PHYS_OFFSET EQU 80000000h
OFFSET32 EQU <OFFSET FLAT:>
;vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv
_DATA SEGMENT DWORD USE32 PUBLIC 'DATA'
;^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
; This GDT is only used by _RebootHandler to set the correct GDT during the warm reboot path
GDT_Data LABEL DWORD
db 0, 0, 0, 0, 0, 0, 0, 0 ; First GDT entry always unused
CS_FLAT_SEL EQU ($-GDT_Data)
db 0FFh, 0FFh, 00h, 00h, 00h, 10011010b, 11001111b, 00h ; Code
DS_FLAT_SEL EQU ($-GDT_Data)
db 0FFh, 0FFh, 00h, 00h, 00h, 10010010b, 11001111b, 00h ; Data
GDT_TABLE_SIZE = $ - OFFSET GDT_Data
GDTPtr LABEL FWORD
dw GDT_TABLE_SIZE - 1 ; Limit of 0 = 1 byte
dd OFFSET GDT_Data
_DATA ENDS
ASSUME CS: FLAT, DS: FLAT, SS: FLAT
;vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv
_TEXT SEGMENT para public 'TEXT'
;^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
public _OEMAddressTable
public _IdentifyCpu
;-------------------------------------------------------------------------------
;-------------------------------------------------------------------------------
_IdentifyCpu PROC NEAR ; COMDAT
push ebx
cli
xor edx, edx ; initialize return value to 0
pushfd ; Save EFLAGS to stack
pop eax ; Store EFLAGS in EAX
mov ecx, eax ; Save in ECX for testing later
xor eax, 00200000h ; Switch bit 21
push eax ; Copy changed value to stack
popfd ; Save changed EAX to EFLAGS
pushfd ; Push EFLAGS to top of stack
pop eax ; Store EFLAGS in EAX
cmp eax, ecx ; See if bit 21 has changed
jz cpuid_ret ; If no change,no CPUID
; call cpuid with eax == 1 to get capability info
mov eax, 1
DB 00fH
DB 0a2H
cpuid_ret:
mov eax, edx
pop ebx
ret 0
_IdentifyCpu ENDP
;-------------------------------------------------------------------------------
;-------------------------------------------------------------------------------
LIN_TO_PHYS_MASK EQU 7FFFFFFFh
PG_MASK EQU 80000000h
CD_MASK EQU 40000000h
extrn _dwRebootAddress:near
extrn _KernelInitialize:near
;-------------------------------------------------------------------------------
;-------------------------------------------------------------------------------
_RebootHandler PROC NEAR PUBLIC
cli
;
; Get the linear address of the page directory.
;
mov ebx, cr3
or ebx, LIN_TO_PHYS_OFFSET
;
; Create the identity-mapped addresses (physical = linear)
;
mov ecx, OFFSET32 IdentityMapped
mov edx, ecx
and edx, LIN_TO_PHYS_MASK
;
; 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
;
; Copy the page directory entry for the current linear
; address to the physical address.
;
mov eax, DWORD PTR [ebx][ecx]
mov DWORD PTR [ebx][edx], eax
;
; Move execution to the identity-mapped physical address.
;
mov edx, OFFSET32 IdentityMapped
and edx, LIN_TO_PHYS_MASK
jmp edx
IdentityMapped:
mov edx, OFFSET32 PagingDisabled
and edx, LIN_TO_PHYS_MASK
mov eax, cr0
and eax, not PG_MASK ; Disable paging
or eax, CD_MASK ; Disable cache
mov cr0, eax ; Apply new system settings
wbinvd ; Flush the cache
mov ebx, cr3
mov cr3, ebx ; Flush the TLB
and eax, not CD_MASK ; Re-enable cache
mov cr0, eax ; Apply new system settings
jmp edx ; Far jump to purge any prefetch state.
align 4
PagingDisabled:
;
; Move the stack pointer to the physical address.
;
mov eax, esp
and eax, LIN_TO_PHYS_MASK
mov esp, eax
INITIAL_CR0 EQU 00000011h
INITIAL_CR3 EQU 00000000h
INITIAL_CR4 EQU 00000000h
INITIAL_EFLAGS EQU 00007046h
mov eax, INITIAL_CR0
mov cr0, eax
mov eax, INITIAL_CR3
mov cr3, eax
.586p
mov eax, INITIAL_CR4
mov cr4, eax
.486p
mov eax, INITIAL_EFLAGS
lgdt FWORD PTR [GDTPtr] ; Load the GDTR
push eax
popfd
;
; Read from RAM the address we are jumping to.
;
mov edx, _dwRebootAddress
and edx, LIN_TO_PHYS_MASK
mov ebx, dword ptr [edx]
and ebx, LIN_TO_PHYS_MASK
;
; Jump to the first instruction.
;
jmp ebx
_RebootHandler ENDP
;-------------------------------------------------------------------------------
;-------------------------------------------------------------------------------
_StartUp PROC NEAR PUBLIC
cli
;
; The following strange code is used to get the Physical Address of _PAOfStart.
; The trick is that "call" will pushed the return address onto stack, which will
; be the the Physical address of _PaStart. We then pop the stack to get the Physical
; address.
;
call _IdentifyCpu
mov edi, eax ; argument to _KernelInitialize, edi = cpu capability bits
call _PAOfStart
_PAOfStart:
pop esi ; (esi) = PA of _PAStart
add esi, OFFSET32 _OEMAddressTable
sub esi, OFFSET32 _PAOfStart ; (esi) = PA of OEMAddressTable
; argument to KernelInitialize:
; (esi) = Physical Address of OEMAddressTable
; (edi) = CPU capability bits
;
jmp _KernelInitialize
align 4
_OEMAddressTable:
;
; OEMAddressTable defines the mapping between Physical and Virtual Address
; o MUST be in a READONLY Section
; o First Entry MUST be RAM, mapping from 0x80000000 -> 0x00000000
; o each entry is of the format ( VA, PA, cbSize )
; o cbSize must be multiple of 4M
; o last entry must be (0, 0, 0)
; o must have at least one non-zero entry
; RAM 0x80000000 -> 0x00000000, size 64M
dd 80000000h, 0, 04000000h
; FLASH and other memory, if any
; dd FlashVA, FlashPA, FlashSize
; Last entry, all zeros
dd 0, 0, 0
_StartUp ENDP
;-------------------------------------------------------------------------------
;-------------------------------------------------------------------------------
_CallBios32 PROC NEAR PUBLIC
RegisterArray equ 8
CallingAddress equ 12
push ebp
mov ebp,esp
push ebx
push ecx
push edx
push esi
push edi
; Load Register.
mov ebx,DWORD PTR RegisterArray[ebp]
mov eax,DWORD PTR [ebx]
mov ecx,DWORD PTR [ebx+8]
mov edx,DWORD PTR [ebx+12]
mov esi,DWORD PTR [ebx+16]
mov edi,DWORD PTR [ebx+20]
mov ebx,DWORD PTR [ebx+4]
; Calling into BIOS32
push ebp
mov ebp,DWORD PTR CallingAddress[ebp]
push cs
call ebp
pop ebp
;Save Register
push ebx
mov ebx,DWORD PTR RegisterArray[ebp]
mov DWORD PTR [ebx],eax
mov DWORD PTR [ebx+8],ecx
mov DWORD PTR [ebx+12],edx
mov DWORD PTR [ebx+16],esi
mov DWORD PTR [ebx+20],edi
pop eax
mov DWORD PTR [ebx+4],eax
; returning
pop edi
pop esi
pop edx
pop ecx
pop ebx
pop ebp
jc CallBios32_Fails
xor eax,eax
inc eax
ret 0
CallBios32_Fails:
xor eax,eax
ret 0
_CallBios32 ENDP
;-------------------------------------------------------------------------------
;-------------------------------------------------------------------------------
_GetDS PROC NEAR PUBLIC
push ds
pop eax
ret 0
_GetDS ENDP
_TEXT ENDS
END
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -