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...
Leave a Comment