【译】x86程序员手册40-10.5初始化的例子

时间:2023-02-07 17:50:35

10.5 Initialization Example
初始化的例子

译注:本来想把这个例子全部注释完,但由于对intel汇编实不熟悉,有太多的伪指令,本人也是免强看懂,所以就不再做翻译了。

 

$TITLE ('Initial Task')        #此处title为开始标识,$符号表示取地址
NAME    INIT                #为一段程序命名
init_stack  SEGMENT RW            #定义栈段 可读写 标识符为init_stack
DW  20  DUP(?)                #保留20个双字位置
tos         LABEL   WORD        #定义一个标号tos,类型为字
init_stack  ENDS            #栈段init_stack定义结束 
init_data   SEGMENT RW PUBLIC        #定义数据段 公共 可读写 标识符为init_data
DW  20  DUP(?)                #段长度20个双字,即重复保留20个双字
init_data   ENDS            #数据段定义结束
init_code   SEGMENT ER PUBLIC        #代码段开始 可执行,只读,公共
ASSUME      DS:init_data        #设定此时的数据段为上面定义的数据段
nop
nop
nop
init_start:                #入口点标识符
; set up stack
mov ax, init_stack            #设置栈,将标识符init_stack放入ax
mov ss, ax                #设置栈段寄存器
mov esp, offset tos            #设置栈顶指针为tos的偏移,栈是高向低
mov a1,1                #al中放1
blink:                    #标号blink
xor a1,1                #al清0
out 0e4h,a1                #向0e4H端口输入al中值,此时al = 0
mov cx,3FFFh                #cx = 3FFFh
here:                    #标号here
dec cx                    #cx = cx -1
jnz here                #ZF位不等0, 则跳转到here标号处
jmp SHORT blink                #跳到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 ROM code 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
; 32-Gigabyte data segment based at 0
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