Text Mode Cursor

From OSDev.wiki
Revision as of 01:34, 18 October 2017 by osdev>Davidaylaian (Rewrote most of the page)
Jump to navigation Jump to search

Moving the Cursor

With the BIOS

To move the cursor with the BIOS, use int 0x10 (the interrupt for screen functions). These are the registers used:

  • AH = 0x02
  • BH = display page (usually, if not always 0)
  • DH = row
  • DL = column

Without the BIOS

Without BIOS access, moving the cursor requires sending data directly to the hardware.

Source in C

void update_cursor(int x, int y)
{
	uint16_t pos = y * VGA_WIDTH + x;

	outb(0x3D4, 0x0F);
	outb(0x3D5, (uint8_t) (pos & 0xFF));
	outb(0x3D4, 0x0E);
	outb(0x3D5, (uint8_t) ((pos >> 8) & 0xFF));
}

Note that the x and y positions start from 0 in the top-left corner. Keep in mind you don't need to update this every time a new character is displayed. It would be faster to instead only update it after printing an entire string or until a user prompt.

Source in Assembly

Since BIOS services cannot be accessed in Long Mode, the following routine shows how to move cursor without BIOS in VGA text 80x25 (can be altered a bit to fit protected mode):

; Set cursor position (text mode 80x25)
; @param BL The row on screen, starts from 0
; @param BH The column on screen, starts from 0
set_cursor:
                pushfq
                push rax
                push rbx
                push rcx
                push rdx

                ; unsigned short position = (row*80) + col
                ; AX will contain 'position'
                mov ax, bx
                and ax, 0ffh             ; set AX to 'row'
                mov cl, 80
                mul cl                   ; row * 80
                
                mov cx, bx
                shr cx, 8                ; set CX to 'col'
                add ax, cx               ; + col
                mov cx, ax               ; store 'position' in CX
 
                ; cursor LOW port to vga INDEX register
                mov al, 0fh
                mov dx, 3d4h             ; VGA port 3D4h
                out dx, al
                
                mov ax, cx               ; restore 'postion' back to AX
                mov dx, 3d5h             ; VGA port 3D5h
                out dx, al               ; send to VGA hardware
    
                ; cursor HIGH port to vga INDEX register
                mov al, 0eh
                mov dx, 3d4h             ; VGA port 3D4h
                out dx, al
                
                mov ax, cx               ; restore 'position' back to AX
                shr ax, 8                ; get high byte in 'position'
                mov dx, 3d5h             ; VGA port 3D5h
                out dx, al               ; send to VGA hardware

                pop rdx
                pop rcx
                pop rbx
                pop rax
                popfq
                ret

Setting the Cursor Start and End Scanlines

To set the cursor start and end scanlines, use the Cursor Start Register (0x0A) and the Cursor End Register (0x0B). The highest scanline is 0 and the lowest scanline is the maximum scanline (usually 15).

Source in C

void enable_cursor(uint8_t cursor_start, uint8_t cursor_end)
{
        outb(0x3D4, 0x0A);
        outb(0x3D5, (inb(0x3D5) & 0xC0) | cursor_start);

        outb(0x3D4, 0x0B);
        outb(0x3D5, (inb(0x3E0) & 0xE0) | cursor_end);
}

To make the cursor be a block instead of a line, try enable_cursor(0, 15).

Disabling The Cursor

With the BIOS

To move the cursor with the BIOS, use int 0x10 (the interrupt for screen functions). These are the registers used:

  • AH = 0x01
  • CH = 0x3F (bits 0-7 unused, bit 5 disables cursor, bits 0-4 control cursor shape)

Without the BIOS

Without BIOS access, disabling the cursor requires sending data directly to the hardware.

Source in C

void disable_cursor()
{
	outb(0x3D4, 0x0A);
	outb(0x3D5, 0x20);
}

Source in Assembly

disable_cursor:
	pushf
	push rax
	push rdx

	mov dx, 0x3D4  ; one of VGA's Index registers controller
	mov al, 0xa    ; index 0xa is the LOW cursor shape register
	out dx, al 

	inc dx         ; one of VGA's data registers, port 0x3D4, allows reads and writes to VGA's registers
	mov al, 0x3F   ; bits 6-7 must be 0, if bit 5 set the cursor is disabled, bits 0-4 control the cursor shape
	out dx, al
	pop rdx
	pop rax
	popf
	ret

See Also

External Links