【译】x86程序员手册40-10.5初始化的例子
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