Bootsector executed, CPU in pmode: How to write a string on the screen?

Login asks:

Hi, I've been written a bootsector that initalys a stack, DS segment, end put the CPU in Protected Mode. But when the CPU is in Pmode, I can't use the int 10h func. 0Eh for writting characters on the screen. How can I do ???? PLEASE? HEEELLLLLPPPP

My answer:

The easiest way to write characters or strings on the screen directly after switching into PMode is to assign the value 0xB800 to FS while in real-mode. When you switch into PMode, FS is not a valid GDT selector but you can use it as well!

At boot time, the console is 80x25 16-bit wide characters. That means the offset of the 16-bit character will be (x+160*y). I use 32-bit integer to store 2-byte strings for debuging purpose during boot.

Example in NASM syntax:

; fs=0xb800 (before switching into pm) 
        mov     eax, dword [debug_ok] 
        mov     [fs:160], eax 
; ... 
debug_ok: 
        db 'O',0x0a,'K',0x0a ; 'OK' in green on black 

The attribute byte format is:

bits 7    6    5    4    3    2    1    0 
  +----+----+----+----+----+----+----+----+ 
  | BL |  BACKGROUND  |    FOREGROUND     | 
  +----+--------------+-------------------+ 
BL=1 makes the character blinking. 
Values for BACKGROUND and FOREGROUND: 
0x0 BLACK     (default for BACKGROUND in BIOS) 
0x1 BLUE 
0x2 GREEN 
0x3 CYAN 
0x4 RED 
0x5 MAGENTA 
0x6 BROWN 
0x7 LIGHTGRAY (default for FOREGROUND in BIOS) 
; as BACKGROUND is 3-bit, the following colours are not available 
; for background 
0x8 DARKGRAY 
0x9 LIGHTBLUE 
0xa LIGHTGREEN (I love that... It remembers me the Amstrad ;) 
0xb LIGHTCYAN 
0xc LIGHTRED 
0xd LIGHTMAGENTA 
0xe YELLOW 
0xf WHITE 
; (from conio.h (djgpp)) 

Here is a cputs() style function (pmode). It takes an ASCIIZ string in ESI and puts it at (X+Y*80) position stored in ECX. It does not need FS to equal 0xb800 but it would have been shorter.

write: 
        lodsb ; per character write 
        mov     ah, 0x0a ; LIGHTGREEN on BLACK, no BLinking 
        and     al,al 
        jz      .wri_1 
        call    .wri_2 
        inc     ecx 
        jmp     write 
.wri_2 
        push    ecx 
        push    edi 
        mov     edi, 0xB8000 
        shl     ecx, 1 ; 16-bit characters 
        mov     word [edi+ecx], ax 
        pop     edi 
        pop     ecx 
.wri_1 
        ret 

Example call:

        mov     ecx, 8*80 ; print it at (0,8) 
        mov     esi, msg 
        call    write 
        ; 
        msg:    db 'message', 0x00 

Hope this helped...

Powered by Blogger.