Page 1 of 1

Change VGA font

Posted: Sun May 27, 2012 1:26 am
by suslik
Hi!

I've read this:
http://forum.osdev.org/viewtopic.php?f=1&t=20862
http://www.osdever.net/FreeVGA/vga/vgafunc.htm
and wanted to program VGA font loading in my OS.

Here is my code:

Code: Select all

#include <system.h>
#include <inline.h>

#define COLUMNS 80
#define ROWS 25
#define VIDEO_ADDR 0xB8000

/* @iport - index port, @iport + 1 - data port */
static inline void vga_write_reg(u16_t iport, byte_t reg, byte_t val){
	to_port_b(iport, reg); /* Select register */
	to_port_b(iport + 1, val); /* Do writing through data port */
}
/* @iport - index port, @iport + 1 - data port */
static inline byte_t vga_read_reg(u16_t iport, byte_t reg){
	to_port_b(iport, reg); /* Select register */
	return from_port_b(iport + 1); /* Do reading through data port */
}

#define VGA_SEQ_INDEX_PORT 0x3C4
#define VGA_SEQ_DATA_PORT 0x3C5

#define VGA_GC_INDEX_PORT 0x3CE
#define VGA_GC_DATA_PORT 0x3CF

#define VGA_CRTC_INDEX_PORT 0x3D4
#define VGA_CRTC_DATA_PORT 0x3D5

#define VGA_SEQ_MAP_MASK_REG 0x02
#define VGA_SEQ_CHARSET_REG 0x03
#define VGA_SEQ_MEMORY_MODE_REG 0x04

#define VGA_GC_READ_MAP_SELECT_REG 0x04
#define VGA_GC_GRAPHICS_MODE_REG 0x05
#define VGA_GC_MISC_REG 0x06

#define BYTES_PER_GLYPTH 16
#define BYTES_SKIP 16
#define CHARSET_LENGTH 256
#define FONT_SIZE CHARSET_LENGTH * BYTES_PER_GLYPTH

static void set_font(unsigned char font[FONT_SIZE]){
	int i, j;
	unsigned char *p = (unsigned char *)0xB8000;
	byte_t mem_mode, graphics_mode;
	
	/* Panel 2 write enable */
	vga_write_reg(VGA_SEQ_INDEX_PORT, VGA_SEQ_MAP_MASK_REG, 0x04);
	
	/* To be shure, that the first font in the plane 2 is selected */
	vga_write_reg(VGA_SEQ_INDEX_PORT, VGA_SEQ_CHARSET_REG, 0x00);
	
	mem_mode = vga_read_reg(VGA_SEQ_INDEX_PORT, VGA_SEQ_MEMORY_MODE_REG);
	vga_write_reg(VGA_SEQ_INDEX_PORT, VGA_SEQ_MEMORY_MODE_REG, 0x06);
	
        /* I think this line is unnecessary */
	vga_write_reg(VGA_GC_INDEX_PORT, VGA_GC_READ_MAP_SELECT_REG, 0x02);
	
	graphics_mode = vga_read_reg(VGA_GC_INDEX_PORT, VGA_GC_GRAPHICS_MODE_REG);
	vga_write_reg(VGA_GC_INDEX_PORT, VGA_GC_GRAPHICS_MODE_REG, 0x00);
	
        /* And this line is unnecessary too, since I now, that address is 0xB8000 */
	vga_write_reg(VGA_GC_INDEX_PORT, VGA_GC_MISC_REG, 0x0C);
	
	/* Write charmap */
	for(i = 0; i < CHARSET_LENGTH; i++){
		for(j = 0; j < BYTES_PER_GLYPTH; j++){
			*p = *font;
			++p;
			++font;
		}
		p += BYTES_SKIP;
	}
	
	/* Restore VGA to normal operation */
	
	/* Panels 0 and 1 write enable */
	vga_write_reg(VGA_SEQ_INDEX_PORT, VGA_SEQ_MAP_MASK_REG, 0x03);
	vga_write_reg(VGA_SEQ_INDEX_PORT, VGA_SEQ_MEMORY_MODE_REG, mem_mode);
	
	vga_write_reg(VGA_GC_INDEX_PORT, VGA_GC_READ_MAP_SELECT_REG, 0x00);
	vga_write_reg(VGA_GC_INDEX_PORT, VGA_GC_GRAPHICS_MODE_REG, graphics_mode);
	vga_write_reg(VGA_GC_INDEX_PORT, VGA_GC_MISC_REG, 0x0C);
}
I tried this on bochs and real PC, but the font doesn't change! OK, I copied and pasted the code from http://forum.osdev.org/viewtopic.php?f=1&t=20862, but the same - the font stay unchanged. I breaked my mind, but I can't guess what's wrong.

Please, I need help.

P.S: If it is important: I'm working in the 32-bit protected mode.

Re: Change VGA font

Posted: Sun May 27, 2012 4:57 am
by Combuster
I checked the register writes and couldn't find anything wrong within the posted code.

What actually is your custom font? The ready-to-use fonts you find on the web are typically the same as what you already have in video memory - which means there is no change to be expected.

Re: Change VGA font

Posted: Sun May 27, 2012 5:22 am
by suslik
Thank you for reply,

I took /usr/share/kbd/consolefonts/koi8r-8x16.gz (4096 bytes long) from my Linux installation, unpacked it and transformed into font.c file: unsigned char font[] = {0x00, ...}.

Bochs VGA BIOS's font isn't equal to koi8r-8x16.gz, since I've tried 2 Bochs (on my Linux host and my Windows host) with different VGA BIOS's fonts.

Any ideas?

Re: Change VGA font

Posted: Sun May 27, 2012 6:45 am
by suslik
OK, I've tried to load garbage instead of a font on a real PC... but nothing changed!

1) I begin write font from address 0xB8000 and no outputed text on my console become corrupted, so I can assume that I really write to plane 2 of VGA memory.

2) I programed exactly the same function as set_font(): get_font(). And tried: set_font(my_font), get_font(temp_buffer), memcmp(my_font, temp_buffer). And my_font and temp_buffer were the same. So, I can assume that I really write my font to plane 2.

3) In set_font() I set the value of Character Set register of the Sequencer to 0x00 - so Character Set A and Character Set B points to 0x0000 - 0x1FFF (where I write my font).

What I should do? What values I should check?
May be I something miss in theory of font loading in VGA?
May be GRUB (that I use to load my kernel) switches something in VGA?

Re: Change VGA font

Posted: Sun May 27, 2012 9:14 am
by Combuster
I just converted your code to something I could actually run and came up with the following bit of bootsector code:

Code: Select all

        MOV AX, 0xB800
        MOV ES, AX

        MOV DX, 0x3C4
        MOV AX, 0x0402          ; seq.mapmask = !0, !1, 2, !3
        OUT DX, AX
        MOV AX, 0x0003          ; seq.font A=0 B=0
        OUT DX, AX
        MOV AX, 0x0604          ; seq.memmode = O/E off, chain4 off, ext on
        OUT DX, AX

        MOV DX, 0x3CE
        MOV AX, 0x0005          ; gx.modereg = !256, !shift, !OE, writemode_0
        OUT DX, AX
        MOV AX, 0x0C06          ; gx.miscreg = map_b8000, !HostOE, !graphics
        OUT DX, AX

        ; set font to garbage
        MOV CX, 0x1000
        XOR DI, DI
.loop:  MOV AL, CL
        MOV [ES:DI], CL
        INC DI
        DEC CX 
Which worked as expected. Note that gx[6] = 0x0C doesn't just fix the write address, but also fixes the Odd/Even bit to a known value, so I'd probably keep that. The read map is only needed for reading.

At any rate, I have absolutely no reason left to believe the error is in the code posted. But since reading and writing responds like actual memory, I suspect that you're not actually hitting video memory (or even overwriting it later). What are your paging and segment configurations like? Can you enable debug logging of bochs' VGA plugin and check that the port writes are actually performed as expected?

Re: Change VGA font

Posted: Tue May 29, 2012 3:24 pm
by suslik
Combuster, thank you for your help. Now I realized that my code loading font is right and the problem was in: 1) I used bochs in linux console (not X-System) => font changes were impossible, 2) I used this code to check that the font has been changed:

Code: Select all

puts("Old font:\n");
for(i = 0; i < 256; i++)
putchar(i);
set_font(my_font);
puts("\nNew font:\n");
for(i = 0; i < 256; i++)
putchar(i);
This check is wrong, but I realize it only now. I'm ashamed of myself.

Now all is OK, and I did a funny trick: I took a monochrome bmp-file, divided it into small glyphes and loaded them as font in text mode 80x25. Screenshot of the result you can see in the attachment. I think the result is not bad.

Re: Change VGA font

Posted: Tue May 29, 2012 5:10 pm
by Combuster
You're welcome.
suslik wrote:I think the result is not bad.
For a quick improvement on the character art, set the 9/8 dot mode register to 8 to remove the red lines, and set the dot clock to 25 MHz to prevent real screens from complaining about the altered frequency. :wink:

Re: Change VGA font

Posted: Wed May 30, 2012 3:22 am
by turdus
suslik wrote:Screenshot of the result you can see in the attachment. I think the result is not bad.
You can make it better if you turn off 9th pixel (instead of 9x16 you'll have 8x16 characters). That will make those vertical lines disappear.

Re: Change VGA font

Posted: Wed May 30, 2012 9:27 pm
by suslik
OK, I did it. Much better, you are right. BUT: without those vertical lines there is no mention of the text mode, 'Che' looks like in graphics mode now. I think some difference should be to proof everyone that this is text mode.

Re: Change VGA font

Posted: Thu May 31, 2012 5:41 am
by Nable
Use less than 256 chars for tiles. The best variant is to leave as much from standard font as possible, rendering the picture with mostly standard characters. Dithering is your friend.
Then you can add some text in free space of the screen.