编写2阶段引导加载程序并查看输出后:
第一阶段的输出(使用BIOS'int 10h
中断产生)与通过在保护模式下直接访问视频内存获得的白色(或灰色?)不同。
为什么会有所不同? BIOS使用什么视频模式?
答案 0 :(得分:2)
BIOS以模式0启动,颜色属性字节为0x07(黑色背景,灰色前景)。第二个白色似乎是0x0F,因为亮位被设置(0x08是亮度位,只需将其添加到颜色以获得鲜艳的颜色)。
答案 1 :(得分:0)
当IBM PC兼容计算机启动时,POST后,当BIOS准备好加载启动加载程序时,BIOS视频模式为3(二进制11)。我已经在几台计算机和Bochs 2.6.8上使用以下引导扇区程序(为FASM编写)对此进行了测试。
;
;
; This boot sector program invokes BIOS INT 10h AH=0Fh (get current video mode) and displays the results to the screen
;
;
; Preliminary directives so fasm knows how to generate the machine code
;
format binary ; this directive tells fasm to write the generated code as a flat binary file
use16 ; this directive tells fasm to generate 16-bit code
org 0x7C00 ; org directive tells fasm that the program will be loaded at 0x7C00, where the BIOS hands over control to the bootstrap code
;
;
; Get current video mode (INT 10h, function AH=0Fh)
;
mov ah,0xF ; set AH to 0xF (AH=0Fh is the function for getting the current video mode)
int 0x10 ; invoke BIOS interrupt 10h, function AH=0Fh to get the current video mode
;
;
; Display results to the screen
;
; Save the results for printing later
;
mov dh,al ; save AL (the current video mode) to DH
push bx ; save BH to the stack
push ax ; save AH to the stack
;
; Display the value saved to DH (i.e. the current video mode, which was copied from AL to DH above)
;
xor ax,ax ; set AX to 0 in order to set DS to 0
mov ds,ax ; DS = 0 (SI works with DS to point to the address created by DS:SI)
mov si,vid_mode_prompt ; set SI to point to the first character of the message to be printed
mov cx,12 ; set the counter (CX) to match the number of characters to print
call print_string_procedure ; save to the stack the address of the next instruction, then jump to the procedure called by this instruction
call procedure_for_printing_DH ; save to the stack the address of the next instruction, then jump to the procedure called by this instruction
;
; Display the value for the number of character columns used by the current video mode (pushed onto the stack from AH)
;
;xor ax,ax ; set AX to 0 in order to set DS to 0 (commented out, because AX is not needed to set DS, since DS is probably already 0)
;mov ds,ax ; DS = 0 (SI works with DS to point to the address created by DS:SI) (commented out, because DS is probably already 0)
mov si,num_col_prompt ; set SI to point to the first character of the message to be printed
mov cx,13 ; set the counter (CX) to match the number of characters to print
call print_string_procedure ; save to the stack the address of the next instruction, then jump to the procedure called by this instruction
pop dx ; copy to DH the number of columns previously saved to the stack from AH
call procedure_for_printing_DH ; save to the stack the address of the next instruction, then jump to the procedure called by this instruction
;
; Display the value for the active display page (pushed onto the stack from BH)
;
;xor ax,ax ; set AX to 0 in order to set DS to 0 (commented out, because AX is not needed to set DS, since DS is probably already 0)
;mov ds,ax ; DS = 0 (SI works with DS to point to the address created by DS:SI) (commented out, because DS is probably already 0)
mov si,display_page_prompt ; set SI to point to the first character of the message to be printed
mov cx,17 ; set the counter (CX) to match the number of characters to print
call print_string_procedure ; save to the stack the address of the next instruction, then jump to the procedure called by this instruction
pop dx ; copy to DH the value of the active display page
call procedure_for_printing_DH ; save to the stack the address of the next instruction, then jump to the procedure called by this instruction
;
;
; End of program
;
end_of_program: ; label for this section of code
hlt ; stops instruction execution and places the processor in a halted state
jmp end_of_program ; jump to the label 'end_of_program'
;
;
;
;
; Procedures called by the program
;
;
print_string_procedure: ; label for this section of code
;pusha ; save all 8 general registers to the stack (commented out, because it is not necessary to save the values of the general registers)
mov ah,0xE ; set AH to 0Eh (i.e. select teletype output)
xor bh,bh ; set display page number to 0
start_of_print_loop: ; label for this section of code
lodsb ; load string byte (i.e. copy the string element pointed to by DS:SI to AL)
int 0x10 ; invoke BIOS interrupt 10h, function AH=0Eh to display the ASCII character stored in AL
loop start_of_print_loop ; decrement CX by 1, then jump to the specified label until CX=0
;popa ; pop the contents of all eight general registers back from the stack (commented out, because popa corresponds with pusha, which has been commented out above)
ret ; transfer control back to the program that invoked the procedure using the address that was stored on the stack by the call instruction
;
procedure_for_printing_DH: ; label for this section of code
;pusha ; save all 8 general registers to the stack (commented out, because it is not necessary to save the values of the general registers)
;mov ah,0xE ; set AH to 0Eh (i.e. select teletype output) (commented out, because the value in AH is already 0Eh)
;xor bh,bh ; set display page number to 0 (commented out, because the value in BH is already 0)
mov cx,4 ; set the counter (CX) to match the number of characters to print
call start_print_DH_loop ; save to the stack the address of the next instruction, then jump to the procedure called by this instruction
mov al,0x20 ; set AL to print a space (ASCII code for a space is 0x20)
int 0x10 ; invoke BIOS interrupt 10h, function AH=0Eh to display the ASCII character stored in AL
mov cx,4 ; set the counter (CX) to match the number of characters to print
call start_print_DH_loop ; save to the stack the address of the next instruction, then jump to the procedure called by this instruction
;popa ; pop the contents of all eight general registers back from the stack (commented out, because popa corresponds with pusha, which has been commented out above)
ret ; transfer control back to the program that invoked the procedure using the address that was stored on the stack by the call instruction
;
start_print_DH_loop: ; label for this section of code
shl dh,1 ; shifts the bits in the DH register to the left by one bit; the last exited bit will be stored to the CF flag
setc al ; sets the AL register to match the value of the CF flag
add al,0x30 ; convert the number in AL (0 or 1) to ASCII
int 0x10 ; invoke BIOS interrupt 10h, function AH=0Eh to display the ASCII character stored in AL
loop start_print_DH_loop ; decrement CX by 1, then jump to the specified label until CX=0
ret ; transfer control back to the program that invoked the procedure using the address that was stored on the stack by the call instruction
;
;
;
;
; Data used by the program
;
;
vid_mode_prompt:
db 'Video mode: ' ; 12 characters
;
num_col_prompt:
db 0xD,0xA,0xD,0xA,'Columns: ' ; 13 characters
;
display_page_prompt:
db 0xD,0xA,0xD,0xA,'Active page: ' ; 17 characters
;
;
; Padding and magic number
times 510-($-$$) db 0
dw 0xaa55
Screenshot from Bochs 2.6.8 after compiling and running the above program