Question

After writing a 2-stage bootloader and viewing the output :

Output from QEMU

The first stage's output (produced by using BIOS' int 10h interrupt) has a different white (or is it gray?) than the one obtained by directly accessing video memory in protected mode.

Why is this different ? What video mode does BIOS use ?

Was it helpful?

Solution

The BIOS starts up in mode 0, with the color attribute byte as 0x07 (black background, gray foreground). The 2nd white seems to be 0x0F, as the bright bit is set (0x08 is brightness bit, simply add it to the color to get the bright colors).

OTHER TIPS

When an IBM PC compatible computer boots up, after POST, when the BIOS is ready to load the boot loader, the BIOS video mode is 3 (11 in binary). I have tested this using the following boot sector program (written for FASM) on a couple of computers and on Bochs 2.6.8.

;
;
; 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

Information from Wikipedia on INT 10H

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top