This is some code from a old VGA driver of mine so it is not quite as slim as it could be, but it appears to work besides some bugs it might contain.
It does not work under BOCHS for some reason, but it does work under QEMU (which is the only place it has been tested). It is most likely a little bug somewhere in the code. Anyway, it draws two lines that alternate in color. It does this by drawing onto a local frame buffer which is then copied into VGA memory using four planes at four bits per pixel.
Code: Select all
#include <asm/io.h>
#define PICTURE_GFX4BPP6BPC 0x0
#define PICTURE_TEXT1C1A 0x1
struct tPictureInfo{
unsigned long infoType;
unsigned long vMemSize;
unsigned long infoWidth;
unsigned long infoHeight;
unsigned long infoRefresh;
}; typedef struct tPictureInfo PICTUREINFO; typedef struct tPictureInfo* PPICTUREINFO;
#define VGA_GFX_ADDR 0x3CE
#define VGA_GFX_DATA 0x3CF
#define VGA_SEQ_ADDR 0x3C4
#define VGA_SEQ_DATA 0x3C5
#define VGA_GFX_SSR 0x00
#define VGA_GFX_ESRR 0x01
#define VGA_GFX_CCR 0x02
#define VGA_GFX_DRR 0x03
#define VGA_GFX_RMSR 0x04
#define VGA_GFX_GMR 0x05
#define VGA_GFX_MGR 0x06
#define VGA_GFX_CDCR 0x07
#define VGA_GFX_BMR 0x08
#define VGA_SEQ_RR 0x00
#define VGA_SEQ_CMR 0x01
#define VGA_SEQ_MMR 0x02
#define VGA_SEQ_CMSR 0x03
#define VGA_SEQ_SMMR 0x04
#define VGA_DAC_WADDR 0x3C8
#define VGA_DAC_RADDR 0x3C7
#define VGA_DAC_DATA 0x3C9
#define VGA_DAC_STATE 0x3C7
#define VGA_CRT_ADDR 0x3D4
#define VGA_CRT_DATA 0x3D5
#define VGA_CRT_HTR 0x0
#define VGA_CRT_EHDR 0x1
#define VGA_CRT_SHBR 0x2
#define VGA_CRT_EHBR 0x3
#define VGA_CRT_SHRR 0x4
#define VGA_CRT_EHRR 0x5
#define VGA_CRT_VTR 0x6
#define VGA_CRT_MCR 0x17
#define VGA_CRT_OR 0x13
#define VGA_CRT_OFR 0x07
#define VGA_CRT_MSLR 0x09
#define VGA_CRT_VRER 0x11
#define VGA_CRT_ULR 0x14
#define VGA_ATR_ADDRDATA 0x3C0
#define VGA_ATR_READ 0x3C1
#define VGA_ATR_CSR 0x14
#define VGA_ATR_MCR 0x10
#define CLK_25 0x00
#define CLK_28 0x04
#define CLK_U0 0x08
#define CLK_U1 0x0C
inline void vga_atr_w_ip(unsigned short index, unsigned char data){
inb(0x3da);
outb(index, VGA_ATR_ADDRDATA);
outb(data, VGA_ATR_ADDRDATA);
return;
}
inline void vga_atr_w(unsigned short index, unsigned char data){
inb(0x3da);
outb(index|0x20, VGA_ATR_ADDRDATA);
outb(data, VGA_ATR_ADDRDATA);
return;
}
inline unsigned char vga_atr_r_ip(unsigned short index){
inb(0x3da);
outb(index, VGA_ATR_ADDRDATA);
return inb(VGA_ATR_READ);
}
inline unsigned char vga_atr_r(unsigned short index){
inb(0x3da);
outb(index|0x20, VGA_ATR_ADDRDATA);
return inb(VGA_ATR_READ);
}
inline unsigned char vga_seq_r(unsigned short index){
outb(index, VGA_SEQ_ADDR);
return inb(VGA_SEQ_DATA);
}
inline unsigned char vga_gfx_r(unsigned short index){
outb(index, VGA_GFX_ADDR);
return inb(VGA_GFX_DATA);
}
inline unsigned char vga_dac_r(unsigned short index){
return inb(index);
}
inline unsigned char vga_crt_r(unsigned short index){
outb(index, VGA_CRT_ADDR);
return inb(VGA_CRT_DATA);
}
inline void vga_crt_w(unsigned short index, unsigned char data){
outb(index, VGA_CRT_ADDR);
outb(data, VGA_CRT_DATA);
return;
}
inline void vga_dac_w(unsigned short index, unsigned char data){
outb(data, index);
return;
}
inline void vga_seq_w(unsigned char index, unsigned char data){
outb(index, VGA_SEQ_ADDR);
outb(data, VGA_SEQ_DATA);
return;
}
inline void vga_gfx_w(unsigned char index, unsigned char data){
outb(index, VGA_GFX_ADDR);
outb(data, VGA_GFX_DATA);
return;
}
#define EXTCOUNT 0x01 // not correct currently but will work for now. (Actually two that I know of.)
#define CRTCOUNT 0x19
#define SEQCOUNT 0x05
#define ATRCOUNT 0x14
#define GFXCOUNT 0x09
struct tvmode{
PICTUREINFO info;
unsigned char extReg[EXTCOUNT];
unsigned char crtReg[CRTCOUNT];
unsigned char seqReg[SEQCOUNT];
unsigned char atrReg[ATRCOUNT];
unsigned char gfxReg[GFXCOUNT];
} video_clgd5446_vmode[] = {
{
.info = {
.infoType = PICTURE_GFX4BPP6BPC,
.vMemSize = (640*480/2),
.infoWidth = 640,
.infoHeight = 480,
.infoRefresh = 0
},
.extReg = {0x01|0xC0|CLK_25},
.crtReg = {0x5f,0x4f,0x50,0x82,0x55,0x81,0xbf,0x1f,0x0,0x80,0xe,0xf,0x0,0x0,0x0,0x20,0x9c,0x8e,0x8f,0x28,0x7f,0x96,0xb9,0xff,0xff},
.seqReg = {0xff, 0x0, 0xff, 0x0, 0x4},
.atrReg = {0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,0x1,0x0,0xff,0x00},
.gfxReg = {0xff,0,0,0,0,0,0x01,0x00,0xff}
},
{
.info = {
.infoType = PICTURE_TEXT1C1A,
.vMemSize = (80*20*2),
.infoWidth = 80,
.infoHeight = 20,
.infoRefresh = 0
},
.extReg = {0x03|0xC0|CLK_25},
.crtReg = {0x5f,0x4f,0x50,0x82,0x55,0x81,0xbf,0x1f,0x00,0x4f,0x0e,0x0f,0x00,0x00,0x02,0x30,0x9c,0x8e,0x8f,0x28,0x1f,0x96,0xb9,0xa3,0xff},
.seqReg = {0x03,0x00,0x03,0x00,0x02},
.gfxReg = {0x00,0x00,0x00,0x00,0x00,0x10,0x0e,0x0f,0x0ff},
.atrReg = {0,1,2,3,4,5,0x14,7,0x38,0x39,0x3A,0x3B,0x3C,0x3D,0x3E,0x3F,0x0C,0x00,0x0F,0x08}
}
};
static inline void vga_setmode(struct tvmode *mode){
unsigned long x;
// write extension registers
outb(mode->extReg[0], 0x3C2);
// write crt registers
vga_crt_w(0x11, 0x0);
for(x = 0; x < CRTCOUNT; ++x){
vga_crt_w(x, mode->crtReg[x]);
}
// write sequencer registers
for(x = 0; x < SEQCOUNT; ++x){
vga_seq_w(x, mode->seqReg[x]);
}
// write graphic registers
for(x = 0; x < GFXCOUNT; ++x){
vga_gfx_w(x, mode->gfxReg[x]);
}
// reset palette flip-flop
inb(0x3da);
// write attribute palette
for(x = 0; x < 0xF; ++x){
vga_atr_w_ip(x, mode->atrReg[x]);
}
// enable access to attribute palette
outb(0x20, VGA_ATR_ADDRDATA);
// reset palette flip-flop
inb(0x3da);
// write remaining attribute registers
for(; x < ATRCOUNT; ++x){
vga_atr_w(x, mode->atrReg[x]);
}
return;
}
static inline void vga_pixel_4plane_4bpp(void *vmem, unsigned long pixeli, unsigned char color){
unsigned long bytei, biti, bmask;
bytei = (pixeli/8);
biti = (pixeli) - (bytei*8);
bmask = ~(0x80>>biti);
vga_seq_w(VGA_SEQ_MMR, 1);
((unsigned char*)vmem)[bytei] = (((unsigned char*)vmem)[bytei]&bmask) | (color&1) << (7-biti);
vga_seq_w(VGA_SEQ_MMR, 2);
((unsigned char*)vmem)[bytei] = (((unsigned char*)vmem)[bytei]&bmask) | ((color&2)>>1) << (7-biti);
vga_seq_w(VGA_SEQ_MMR, 4);
((unsigned char*)vmem)[bytei] = (((unsigned char*)vmem)[bytei]&bmask) | ((color&4)>>2) << (7-biti);
vga_seq_w(VGA_SEQ_MMR, 8);
((unsigned char*)vmem)[bytei] = (((unsigned char*)vmem)[bytei]&bmask) | ((color&8)>>3) << (7-biti);
return;
}
static void vga_pixel_4plane_4bpp_from(void *lvmem, void *vmem, unsigned long count)
{
unsigned long x, color[8], cc, y, z;
for(z = 0; z < 4; ++z)
{
vga_seq_w(VGA_SEQ_MMR, (1<<z));
for(x = 0; x < count; x += 8)
{
for(y = 0; y < 8; ++y)
{
color[y] = ((unsigned char*)lvmem)[x+y];
}
for(y = 0, cc = 0; y < 8; ++y)
{
cc = ((color[y] << (4+z) >> y) & (0x80 >> y)) | cc;
}
((unsigned char*)vmem)[x/8] = cc;
}
}
return;
}
typedef struct multiboot_info
{
unsigned long flags;
unsigned long mem_lower;
unsigned long mem_upper;
unsigned long boot_device;
unsigned long cmdline;
unsigned long mods_count;
unsigned long mods_addr;
unsigned long ___a;
unsigned long mmap_length;
unsigned long mmap_addr;
} multiboot_info_t;
static unsigned char video_clgd5446_cmap[] = {
0x00, 0x00, 0x00, //00 000
0x00, 0x00, 0xff, //00 001
0x00, 0xff, 0x00, //00 010
0x00, 0xff, 0xff, //00 011
0xff, 0x00, 0x00, //00 100
0xff, 0x00, 0xff, //00 101
0xff, 0xff, 0x00, //00 110
0xff, 0xff, 0xff, //00 111
};
unsigned char lvmem[640*480];
void main(multiboot_info_t* mb)
{
unsigned long x, color;
vga_setmode(&video_clgd5446_vmode[0]);
// load a color map
vga_dac_w(VGA_DAC_WADDR, 0);
for(x = 0; x < (sizeof(video_clgd5446_cmap)/3); ++x){
vga_dac_w(VGA_DAC_DATA, video_clgd5446_cmap[x*3+0]);
vga_dac_w(VGA_DAC_DATA, video_clgd5446_cmap[x*3+1]);
vga_dac_w(VGA_DAC_DATA, video_clgd5446_cmap[x*3+2]);
}
for(; x < 256; ++x){
vga_dac_w(VGA_DAC_DATA, 62);
vga_dac_w(VGA_DAC_DATA, 62);
vga_dac_w(VGA_DAC_DATA, 62);
}
for(color = 0; color < 0xffffffff; ++color)
{
for(x = 0; x < 80; x += 1)
{
lvmem[x] = color*2;
}
for(x = 81; x < 200; x += 1)
{
lvmem[x] = (color + 1) * 2;
}
vga_pixel_4plane_4bpp_from(&lvmem,(void*)0xA0000, 640*80);
for(x = 0; x < 0xFFFFFF; ++x);
}
while(1);
return;
}
You will need to use GRUB to boot the kernel binary with (inside the GRUB console when booting):