📄 startup.asm
字号:
;
;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.
;Copyright (c) 1995-2000 Microsoft Corporation
;
;Module Name: startup.asm
;
;Abstract: Boot loader startup code.
;
;Functions:
;
; Startup
; InPMode
;
;Notes:
;
; Romimage has been modified to support the RESETVECTOR feature for x86 (it's
; usually a PPC-only option). The startup routine and associated GDT need to
; be located in the highest 64KB sector (FFFF.0000 -> FFFF.FFFF) so the reset
; vector only need do a near jump. If we far jump from the reset vector, the
; selector is reloaded and we can't get > 1MB. The RESETVECTOR feature means
; we can build our image for the start of flash (FFFC.0000 for a 256KB part,
; for example), but romimage will *copy* part of this code to the specified
; address.
;
; To use RESETVECTOR, the bib file needs to RESERVE the section and the
; RESETVECTOR= value is assigned there. In the code, three tags, ResetVector,
; ResetVectorAddr, and ResetVectorEnd are use to define the code/data of
; interest. Until the CPU is in protected mode, all addresses need be greater
; than or relative to FFFF.0000. As such, the following need be correctly
; defined:
;
; X86BOOT -> reset jump address
; mov eax, OFFSET GDTPtr
;
; The RESETVECTOR= feature locates StartUp() and the GDT to FFFF.0000. The
; reset vector jumps to FFFF.0000 + GDT + GDTPtr (relative 0x2D). The offset
; to GDTPtr is relative to FFFF.0000 and is FFFF.001A.
;
; If the StartUp routine grows, the GDT changes, or the BIB/RESETVECTOR build
; the StartUp routine to a different location (from FFFF.0000), other changes
; may be required.
.486p
.model FLAT
INCLUDE macro.inc
.code
PUBLIC ResetVectorAddr
PUBLIC ResetVector
PUBLIC ResetVectorEnd
align 4
ResetVectorAddr LABEL DWORD
dd 090000H ; Weird value so 090000H + FFF6.0000H = FFFF.0000H
; and our startup code will be in the upper 64KB.
; FFF6.0000H is ROM_OFFSET/ROMOFFSET.
ResetVector: ; *** Start of code located in upper 64KB ***
align 4
;
; Static GDT mapping:
; - flat 0-4GB code address space
; - flat 0-4GB data address space
;
GDT_Data LABEL DWORD
db 0, 0, 0, 0, 0, 0, 0, 0 ; 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
align 4
;
; GDTR contents (size and GDT pointer)
;
dw 0000h ; Odd word boundary to avoid faults
GDTPtr LABEL FWORD
dw GDT_TABLE_SIZE - 1
dd OFFSET GDT_Data + ROM_OFFSET ; ROM_OFFSET because we're
; pushing RAM image into ROM.
align 4
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; ROM Loader startup routine
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;
StartUp PROC NEAR C PUBLIC
;
; Initialize Debug Serial (must inline because we have no stack)
;
mov dh, 003h
mov dl, 0FBh
mov al, 080h ; Access Baud Divisor
out dx, al
mov dl, 0F8h
mov al, 003h ; 38400 Baud
out dx, al
mov dl, 0F9h
mov al, 000h
out dx, al
mov dl, 0FAh
mov al, 007h ; Enable FIFO if present
out dx, al
mov dl, 0FBh
mov al, 003h ; DLAB = 0, 8 bit, no parity
out dx, al
mov dl, 0F9h
xor al, al ; No interrupts, polled
out dx, al
mov dl, 0FCh
mov al, 003h ; Assert DTR, RTS
out dx, al
IF 0
WriteChar 'B' ; Write status to serial
WriteChar '0'
WriteChar 0dh
WriteChar 0ah
ENDIF
;
; General setup stuff
;
cli ; disable interrupts
cld ; clear direction flag
;
; Configure CPU to use static GDT
;
OpPrefix
;mov eax, OFFSET GDTPtr ; EAX -> Flat GDT Ptr address
; TODO - compute offset - don't hard-code.
mov eax, 0FFFF001AH ; EAX -> Flat GDT Ptr address
; Since the above calculation is assuming a flat address space, we only want
; the offset for the segmented address.
OpPrefix
and eax, 0FFFFh ; Make it relative to funky 0FFFF0000h CS base
AddrPrefix
OpPrefix
lgdt FWORD PTR cs:[eax] ; load the GDTR
;
; Set the PE bit in CR0 (switch to protected mode)
;
; Don't need OpPrefix on mov to/from CR0 - always 32-bit
mov eax, cr0 ; get the current CR0
OpPrefix
or eax, 000000001h
mov cr0, eax ; NOW WE'RE IN PMODE!
OpPrefix
db 0EAh
dd OFFSET InPMode + ROM_OFFSET
dw CS_FLAT_SEL
StartUp ENDP
align 4
;
; The first Protected Mode routine
;
InPMode PROC NEAR
;
; Init the segment registers
;
xor eax, eax
mov al, DS_FLAT_SEL
mov ds, ax
mov es, ax
mov fs, ax
mov gs, ax
mov ss, ax
mov esp, FLAT_STACK_START
;
; Boot progress message
;
IF 0
WriteChar 'B'
WriteChar '1'
WriteChar 0dh
WriteChar 0ah
ENDIF
;
; Configure northbridge
;
; TODO - if we're running in a BIOS environment, we needn't do this. Code can
; be conditionally included.
EXTRN _BridgeConfig:NEAR
EXTRN _BridgePrintConfig:NEAR
NoMemCall _BridgeConfig
IF 0
NoMemCall _BridgePrintConfig
ENDIF
;
; Boot progress message
;
IF 0
WriteChar 'B'
WriteChar '2'
WriteChar 0dh
WriteChar 0ah
ENDIF
;
; Configure cache (enable and set write-through mode)
;
mov ebx, OFFSET CacheEnabled + ROM_OFFSET
mov eax, cr0
and eax, not 060000000h ; clear cache disable and write-through
mov cr0, eax
jmp ebx ; jump to clear prefetch queue
align 4
CacheEnabled:
wbinvd ; clear out the cache
;
; Boot progress message
;
IF 0
WriteChar 'B'
WriteChar '3'
WriteChar 0dh
WriteChar 0ah
ENDIF
;
; Copy ourselves into RAM
;
EXTRN _CopyToRAM:NEAR
call _CopyToRAM
;
; Jump to C main routine...
;
EXTRN _blMain:FAR
mov eax, OFFSET _blMain
jmp eax
ResetVectorEnd:
nop ; Should never get here.
InPMode ENDP
END
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -