Chapter 10 초기화(Initialization)
리셋(RESET) 핀에 신호를 주면, 80386의 특정 레지스터들은 사전 지정한 값으로 셋팅된다. 이러한 값들은 부트스트랩(bootstrap) 프로그램을 실행하는데 적합하지만, 추가적인 초기화는 프로세서의 모든 특성들이 사용되기 전에 소프트웨어적으로 수행되어야 한다.
10.1 리셋 후의 프로세서 상태
레지스터 EAX의 내용은 전원을 킨 이후에 자가 진단 상태에 따라 다르다. 자가 진단은 리셋 과정의 마지막인 ‘BUSY#’ 선언으로 외부에서 요청될 것이다. 80386이 테스트를 통과하면 EAX 레지스터에는 0이 있을 것이다. 자가 진단 후 )이 아닌 값이 EAX에 있다면 80386의 한 부분에 문제가 있다는 것을 나타낸다. 만일 자가 진단이 수행되지 않는다면 리셋 이후 EAX에 어떤 값이 있을지는 알 수 없다.DX에는 라셋 후에 그림 10-1 처럼 컴포넌트 식별자와 리비전(revision) 숫자가 저장된다. DH에는 3이 저장되는데, 이는 80386 컴포넌트를 나타낸다. DL에는 리비전 수준의 고유한 식별자가 있다.
CR0(Control register zero)에는 그림 10-2와 같은 값들이 저장된다. CR0의 ET 비트는 80387이 설정에서 존재가 확인되면(리셋 후에 ERROR# 핀의 상태에 따라) 셋팅된다. ET를 리셋하면 설정에 80287이 포함되었을 수도 있고 보조연산장치가 없을 수도 있다. 소프트웨어적인 테스팅으로 이러한 두 가지 가능성을 구분할 필요가 있다.
남은 레지스터들과 플래그는 아래와 같이 셋팅된다:
EFLAGS =00000002H
IP =0000FFF0H
CS selector =000H
DS selector =0000H
ES selector =0000H
SS selector =0000H
FS selector =0000H
IDTR: =0000H
Base =0
Limit =03FFH
위에서 언급하지 않은 모든 레지스터는 정의되지 않았다.
이러한 셋팅들은 프로세서가 실주소모드(real-address mode)로 인터럽트는 비활성 상태로 시작한다는 것을 의미한다.
그림 10-1. 리셋 후 EDX의 내용
그림 10-2 CR0의 초기 값들
10.2 실주소(Real-Address) 모드용 소프트웨어적 초기화
실주소모드에서는 프로그램이 이 모드에서 가능한 모든 특성들을 사용할 수 있도록 몇몇 구조체가 초기화되어야 한다.
10.2.1 스택(Stack)
스택 세그먼트 레지스터(SS)가 적재되기 전까지 스택을 사용할 수 있는 인스트럭션은 없다. SS 는 램(RAM) 영역을 카리켜야 한다.
10.2.2 인터럽트 테이블(Interrupt Table)
80386 초기 상태는 인터럽트가 비활성된 상태이다; 하지만 프로세서는 예외나 NMI(nonmaskable interrupt)가 발생할 때 계속해서 인터럽트 테이블을 접근하려 할 것이다. 초기화 소프트웨어는 다음 중 하나의 동작을 수행해야 한다.
l IDTR의 한계 값을 0으로 변경. 이렇게 하면 예외나 NMI가 발생했을 때 다운되도록 한다(80386 이 외부에서 종료되는 방식에 관한 HW 매뉴얼 참조)l 예외나 인터럽트가 사용할 인터럽트 테이블에 유효한 인터럽트 처리기(handler)를 가리키는 포인터 입력l IDTR 이 유효한 인터럽트 테이블을 가리키도록 변경
10.2.3 최초 인스트럭션
RESET 후, A{31-20} 주소 줄들은 인스트럭션이 읽어지도록 자동으로 확정된다. 이러한 사실은 CS:IP의 초기값을 사용해서 인스트럭션이 물리 주소 FFFFFFF0H에서 시작한다는 것을 의미한다. Near(intrasegment) 형태의 제어 이동 인스트럭션 형태들이 주소 공간 상위 64K에 있는 다른 주소로 이동하는 데 사용된다. 최초 far(intersemgment) 형태의 JMP나 CALL 인스트럭션은 A{31-20}이 낮은 주소가 되도록 하고 80386은 물리 메모리의 하위 1 메가바이트에 있는 인스트럭션을 계속해서 수행한다. 이러한 A{31-20} 주소 줄의 자동 확정으로 시스템 디자이너는 시스템을 초기화하기 위해 상위 주소 공간에 있는 ROM을 사용할 수 있다.
10.3 보호 모드로의 전환
CR0의 MSW PE비트를 셋팅하면 80386은 보호 모드로 동작한다. 현 특권레벨(CPL)은 0에서 시작한다. 세그먼트 레지스터들은 계속해서 실 주소 모드에서와 동일한 선형 주소를 가리킨다(실 주소모드에서 선형 주소들은 물리 주소와 동일하다).
PE 플래그를 셋팅한 직후, 초기화 코드는 JMP 인스트럭션을 수행해서 인스트럭션 프리패치 큐(prefetch queue)를 비워야 한다. 80386은 인스트럭션들과 주소가 사용되기 전에 이들을 읽어 들이고 해석한다; 하지만 보호모드로 전환한 후에, 이미 읽어 들인 인스트럭션 정보(실주소 모드 해당하는 부부분)는 더 이상 유효하지 않다. JMP는 프로세서로 하여금 유효하지 않은 정보를 버리도록 한다.
10.4 보호 모드 소프트웨어 초기화
보호 모드에 필요한 대부분의 초기화는 보호 모드로 전환 이전이나 이후 모두에서 가능하다. 하지만 보호 모드에서 행해진다면 초기화 프로시져는 아직 초기화되지 않은 보호모드 특성들을 사용해서는 안된다.
10.4.1 인터럽트 기술자 테이블(Interrupt Descriptor Table)
IDTR 은 실주소모드나 보호모드에서 적재될 수 있다. 하지만 보호모드에서 인터럽트 테이블 형식은 실주소모드에서와 다르다. 동시에 모호모드로 전환하고 인터럽트 테이블 형식을 바꾸는 것은 불가능하다.; 그래서 IDTR이 인터럽트 테이블을 선택했다면 어느 순간에는 형식이 맞지 않을 것이라는 것은 피할 수 없다. 이 시점에 발생하는 인터럽트와 예외는 예측 불가능한 결과를 가져올 것이다. 이러한 예측 불가능한 상태를 피하기 인터럽트 핸들러가 동작이 가능하고 유효한 IDT가 보호모드에서 생성될 때까지 인터럽트는 비활성 상태로 유지되어야 한다.
10.4.2 스택
SS 레지스터는 실주소 모드나 보호 모드에서 적재가 가능하다. 실주소모드에서 적재된다면, SS 는 보호 모드로 전환된 이후에도 계속해서 동일한 선형 베이스 주소를 가리키게 된다.
10.4.3 전역 기술자 테이블(Global Descriptor Table)
임의의 세그먼트 레지스터가 보호 모드에서 변경되기 전에, GDT 레지스터는 유효한 GDT를 카리켜야 한다. GDT와 GDTR 초기화는 실주소 모드에서 수행될 것이다. 프로세서가 기술자 접근 비트(accessed bit)를 변경하기 때문에 GDT(LDT뿐만 아니라)는 RAM 영역에 있어야 한다.
10.4.4 페이지 테이블
페이지 테이블과 CR3에 있는 PDBR은 실주소모드나 보호모드에서 초기화가 가능하다; 하지만 CR0의 페이지 활성비트(PG)는 프로세서가 보호모드가 될기 전에는 셋팅이 불가능하다. PG는 PE와 동시에 혹은 나중에 셋팅될 것이다. PG가 셋팅되었을 때, CR3의 PDBR은 이미 유효한 페이지 디렉토리를 가리키는 물리주소로 초기화되있어야 한다. 초기화 과정은 페이징 활성을 전후해서 주소화가 되도록 하기 위해 다음과 같은 과정 중 하나를 사용해야 한다.
l 현재 실행 중인 페이지는 PG 셋팅을 전후해서 물리 주소로 매핑되어야 한다.l JMP 인스트럭션은 PG 셋팅 바로 다음에 있어야 한다.
10.4.5 최초 태스크
초기화 과정은 태스크 레지스터 초기화가 없이 보호모드에서 잠깐 실행될 수 있다; 하지만 최초 태스크로 전환하기 전에 다음 상황이 전체되어야 한다.
l 새로운 태스크에 대한 유효한 태스크 상태 세그먼트(TSS)가 있어야 한다.l 태스크 레지스터는 현재 태스크 상태를 저장할 영역을 가리켜야 한다. 첫 태스크 전환 이후에 이영역에 덥핑된 정보는 필요하지 않고 그 영역은 다른 목적으로 사용될 수 있다.
10.5 초기화 예제
$TITLE ('Initial Task')
NAME INIT
init_stack SEGMENT RW
DW 20 DUP(?)
Tos LABEL WORD
init_stack ENDS
init_data SEGMENT RW PUBLIC
DW 20 DUP(?)
init_data ENDS
init_code SEGMENT ER PUBLIC
ASSUME DS:init_data
nop
nop
nop
init_start:
; set up stack
mov ax, init_stack
mov ss, ax
mov esp, offset tos
mov a1,1
blink:
xor a1,1
out 0e4h,a1
mov cx,3FFFh
here:
dec cx
jnz here
jmp SHORT blink
hlt
init_code ends
END init_start, SS:init_stack, DS:init_data
$TITLE('Protected Mode Transition -- 386 initialization')
NAME RESET
;*****************************************************************
; Upon reset the 386 starts executing at address 0FFFFFFF0H. The
; upper 12 address bits remain high until a FAR call or jump is
; executed.
;
; Assume the following:
;
;
; - a short jump at address 0FFFFFFF0H (placed there by the
; system builder) causes execution to begin at START in segment
; RESET_CODE.
;
;
; - segment RESET_CODE is based at physical address 0FFFF0000H,
; i.e. at the start of the last 64K in the 4G address space.
; Note that this is the base of the CS register at reset. If
; you locate ROMcode above this address, you will need to
; figure out an adjustment factor to address things within this
; segment.
;
;*****************************************************************
$EJECT ;
; Define addresses to locate GDT and IDT in RAM.
; These addresses are also used in the BLD386 file that defines
; the GDT and IDT. If you change these addresses, make sure you
; change the base addresses specified in the build file.
GDTbase EQU 00001000H ; physical address for GDT base
IDTbase EQU 00000400H ; physical address for IDT base
PUBLIC GDT_EPROM
PUBLIC IDT_EPROM
PUBLIC START
DUMMY segment rw ; onLY for ASM386 main module stack init
DW 0
DUMMY ends
;*****************************************************************
;
; Note: RESET CODE must be USEl6 because the 386 initally executes
; in real mode.
;
RESET_CODE segment er PUBLIC USE16
ASSUME DS:nothing, ES:nothing
;
; 386 Descriptor template
DESC STRUC
lim_0_15 DW 0 ; limit bits (0..15)
bas_0_15 DW 0 ; base bits (0..15)
bas_16_23 DB 0 ; base bits (16..23)
access DB 0 ; access byte
gran DB 0 ; granularity byte
bas_24_31 DB 0 ; base bits (24..31)
DESC ENDS
; The following is the layout of the real GDT created by BLD386.
; It is located in EPROM and will be copied to RAM.
;
; GDT[O] ... NULL
; GDT[1] ... Alias for RAM GDT
; GDT[2] ... Alias for RAM IDT
; GDT[2] ... initial task TSS
; GDT[3] ... initial task TSS alias
; GDT[4] ... initial task LDT
; GDT[5] ... initial task LDT alias
;
; define entries in GDT and IDT.
GDT_ENTRIES EQU 8
IDT_ENTRIES EQU 32
; define some constants to index into the real GDT
GDT_ALIAS EQU 1*SIZE DESC
IDT_ALIAS EQU 2*SIZE DESC
INIT_TSS EQU 3*SIZE DESC
INIT_TSS_A EQU 4*SIZE DESC
INIT_LDT EQU 5*SIZE DESC
INIT_LDT_A EQU 6*SIZE DESC
;
; location of alias in INIT_LDT
INIT_LDT_ALIAS EQU 1*SIZE DESC
;
; access rights byte for DATA and TSS descriptors
DS_ACCESS EQU 010010010B
TSS_ACCESS EQU 010001001B
;
; This temporary GDT will be used to set up the real GDT in RAM.
TEMP_GDT LABEL BYTE ; tag for begin of scratch GDT
NULL_DES DESC <> ; NULL descriptor
FLAT_DES DESC <0FFFFH,0,0,92h,0CFh,0>
GDT_eprom DP ? ; Builder places GDT address and limit
; in this 6 byte area.
IDT_eprom DP ? ; Builder places IDT address and limit
; in this 6 byte area.
;
; Prepare operand for loadings GDTR and LDTR.
TGDT_pword LABEL PWORD ; for temp GDT
DW end_Temp_GDT_Temp_GDT -1
DD 0
GDT_pword LABEL PWORD ; for GDT in RAM
DW GDT_ENTRIES * SIZE DESC -1
DD GDTbase
IDT_pword LABEL PWORD ; for IDT in RAM
DW IDT_ENTRIES * SIZE DESC -1
DD IDTbase
end_Temp_GDT LABEL BYTE
;
; Define equates for addressing convenience.
GDT_DES_FLAT EQU DS:GDT_ALIAS +GDTbase
IDT_DES_FLAT EQU DS:IDT_ALIAS +GDTbase
INIT_TSS_A_OFFSET EQU DS:INIT_TSS_A
INIT_TSS_OFFSET EQU DS:INIT_TSS
INIT_LDT_A_OFFSET EQU DS:INIT_LDT_A
INIT_LDT_OFFSET EQU DS:INIT_LDT
; define pointer for first task switch
ENTRY POINTER LABEL DWORD
DW 0, INIT_TSS
;******************************************************************
;
; Jump from reset vector to here.
START:
CLI ;disable interrupts
CLD ;clear direction flag
LIDT NULL_des ;force shutdown on errors
;
; move scratch GDT to RAM at physical 0
XOR DI,DI
MOV ES,DI ;point ES:DI to physical location 0
MOV SI,OFFSET Temp_GDT
MOV CX,end_Temp_GDT-Temp_GDT ;set byte count
INC CX
;
; move table
REP MOVS BYTE PTR ES:[DI],BYTE PTR CS:[SI]
LGDT tGDT_pword ;load GDTR for Temp. GDT
;(located at 0)
; switch to protected mode
MOV EAX,CR0 ;get current CRO
MOV EAX,1 ;set PE bit
MOV CRO,EAX ;begin protected mode
;
; clear prefetch queue
JMP SHORT flush
flush:
; set DS,ES,SS to address flat linear space (0 ... 4GB)
MOV BX,FLAT_DES-Temp_GDT
MOV US,BX
MOV ES,BX
MOV SS,BX
;
; initialize stack pointer to some (arbitrary) RAM location
MOV ESP, OFFSET end_Temp_GDT
;
; copy eprom GDT to RAM
MOV ESI,DWORD PTR GDT_eprom +2 ; get base of eprom GDT
; (put here by builder).
MOV EDI,GDTbase ; point ES:EDI to GDT base in RAM.
MOV CX,WORD PTR gdt_eprom +0 ; limit of eprom GDT
INC CX
SHR CX,1 ; easier to move words
CLD
REP MOVS WORD PTR ES:[EDI],WORD PTR DS:[ESI]
;
; copy eprom IDT to RAM
;
MOV ESI,DWORD PTR IDT_eprom +2 ; get base of eprom IDT
; (put here by builder)
MOV EDI,IDTbase ; point ES:EDI to IDT base in RAM.
MOV CX,WORD PTR idt_eprom +0 ; limit of eprom IDT
INC CX
SHR CX,1
CLD
REP MOVS WORD PTR ES:[EDI],WORD PTR DS:[ESI]
; switch to RAM GDT and IDT
;
LIDT IDT_pword
LGDT GDT_pword
;
MOV BX,GDT_ALIAS ; point DS to GDT alias
MOV DS,BX
;
; copy eprom TSS to RAM
;
MOV BX,INIT_TSS_A ; INIT TSS A descriptor base
; has RAM location of INIT TSS.
MOV ES,BX ; ES points to TSS in RAM
MOV BX,INIT_TSS ; get inital task selector
LAR DX,BX ; save access byte
MOV [BX].access,DS_ACCESS ; set access as data segment
MOV FS,BX ; FS points to eprom TSS
XOR si,si ; FS:si points to eprom TSS
XOR di,di ; ES:di points to RAM TSS
MOV CX,[BX].lim_0_15 ; get count to move
INC CX
;
; move INIT_TSS to RAM.
REP MOVS BYTE PTR ES:[di],BYTE PTR FS:[si]
MOV [BX].access,DH ; restore access byte
;
; change base of INIT TSS descriptor to point to RAM.
MOV AX,INIT_TSS_A_OFFSET.bas_0_15
MOV INIT_TSS_OFFSET.bas_0_15,AX
MOV AL,INIT_TSS_A_OFFSET.bas_16_23
MOV INIT_TSS_OFFSET.bas_16_23,AL
MOV AL,INIT_TSS_A_OFFSET.bas_24_31
MOV INIT_TSS_OFFSET.bas_24_31,AL
;
; change INIT TSS A to form a save area for TSS on first task
; switch. Use RAM at location 0.
MOV BX,INIT_TSS_A
MOV WORD PTR [BX].bas_0_15,0
MOV [BX].bas_16_23,0
MOV [BX].bas_24_31,0
MOV [BX].access,TSS_ACCESS
MOV [BX].gran,O
LTR BX ; defines save area for TSS
;
; copy eprom LDT to RAM
MOV BX,INIT_LDT_A ; INIT_LDT_A descriptor has
; base address in RAM for INIT_LDT.
MOV ES,BX ; ES points LDT location in RAM.
MOV AH,[BX].bas_24_31
MOV AL,[BX].bas_16_23
SHL EAX,16
MOV AX,[BX].bas_0_15 ; save INIT_LDT base (ram) in EAX
MOV BX,INIT_LDT ; get inital LDT selector
LAR DX,BX ; save access rights
MOV [BX].access,DS_ACCESS ; set access as data segment
MOV FS,BX ; FS points to eprom LDT
XOR si,si ; FS:SI points to eprom LDT
XOR di,di ; ES:DI points to RAM LDT
MOV CX,[BX].lim_0_15 ; get count to move
INC CX
;
; move initial LDT to RAM
REP MOVS BYTE PTR ES:[di],BYTE PTR FS:[si]
MOV [BX].access,DH ; restore access rights in
; INIT_LDT descriptor
;
; change base of alias (of INIT_LDT) to point to location in RAM.
MOV ES:[INIT_LDT_ALIAS].bas_0_15,AX
SHR EAX,16
MOV ES:[INIT_LDT_ALIAS].bas_16_23,AL
MOV ES:[INIT_LDT_ALIAS].bas_24_31,AH
;
; now set the base value in INIT_LDT descriptor
MOV AX,INIT_LDT_A_OFFSET.bas_0_15
MOV INIT_LDT_OFFSET.bas_0_15,AX
MOV AL,INIT_LDT_A_OFFSET.bas_16_23
MOV INIT_LDT_OFFSET.bas_16_23,AL
MOV AL,INIT_LDT_A_OFFSET.bas_24_31
MOV INIT_LDT_OFFSET.bas_24_31,AL
;
; Now GDT, IDT, initial TSS and initial LDT are all set up.
;
; Start the first task!
'
JMP ENTRY_POINTER
RESET_CODE ends
END START, SS:DUMMY,DS:DUMMY
'IT, 소프트웨어' 카테고리의 다른 글
| 보안 검색 포털 (0) | 2023.07.13 |
|---|---|
| 9장 예외와 인터럽트(Exceptions and Interrupts) (0) | 2011.05.09 |
| 8장. 입출력(Input/Output) (0) | 2011.02.18 |
| 7. 멀티태스킹(Multitasking) (0) | 2011.02.11 |
| 5장. 메모리 관리 (Memory Management) (0) | 2011.01.27 |