//------------------------------------------------------------------- // newzero.cpp // // This program shows how the VGA's Graphics Controller can be // used to permit an application (with suitable privileges) to // modify a glyph in the system's character generator ram. It // installs a new image for the zero character ('0') which has // ascii code 0x30. For correct operation this program should // be executed in standard 80x25 text mode (VGA mode 3) from a // command shell having 'root' privileges. // // Reference: Richard Wilton, "Programmer's Guide to PC Video // Systems (Second Edition)," Microsoft Press (1994), 294-299. // // NOTE: Run the 'mode3' program to restore the standard zero. // // programmer: ALLAN CRUSE // written on: 04 SEP 2003 // revised on: 09 SEP 2003 //------------------------------------------------------------------- #include // for printf(), perror() #include // for open() #include // for exit() #include // for mmap() #include // for iopl() #define GRAF_PORT 0x3CE // for i/o to the Graphics Controller #define TSEQ_PORT 0x3C4 // for i/o to the VGA Timer-Sequencer unsigned char newglyph[ 16 ] = { 0x00, // 00000000 0x00, // 00000000 0x7C, // 01111100 0x82, // 10000010 0x82, // 10000010 0x82, // 10000010 0x82, // 10000010 0x82, // 10000010 0x82, // 10000010 0x82, // 10000010 0x82, // 10000010 0x7C, // 01111100 0x00, // 00000000 0x00, // 00000000 0x00, // 00000000 0x00 // 00000000 }; void map_device_memory( int base, int size ); int main( int argc, char **argv ) { // map the VGA memory window into the user's address-space int base = 0x000A0000; // beginning of VGA window int size = (128<<10); // length of window = 128K map_device_memory( base, size ); // display some sample text that has a few zeros within it printf( "\033[H\033[J\n\n" ); // start with a clear screen printf( "\nTest message #1: one kilobyte equals 1024 bytes" ); printf( "\nTest message #2: one megabyte equals 1024 kilobytes" ); printf( "\nTest message #3: one gigabyte equals 1024 megabytes" ); printf( "\n\nOK, to see a new glyph for zero, press " ); getchar(); // make sure we are allowed execute i/o instructions if ( iopl( 3 ) ) { perror( "iopl" ); exit(1); } // prologue (makes character ram accessible to the cpu) outw( 0x0100, TSEQ_PORT ); // enter synchronous reset outw( 0x0402, TSEQ_PORT ); // write only to map 2 outw( 0x0704, TSEQ_PORT ); // use sequential addressing outw( 0x0300, TSEQ_PORT ); // leave synchronous reset outw( 0x0204, GRAF_PORT ); // select map 2 for reads outw( 0x0005, GRAF_PORT ); // disable odd-even addressing outw( 0x0006, GRAF_PORT ); // map starts at 0xA000:0000 // load our new image for '0' into character generator ram unsigned char *vram = (unsigned char*)base; int zlocn = 0x30 * 32; for (int i = 0; i < 16; i++) vram[ zlocn + i ] = newglyph[ i ]; // epilogue (makes character ram inaccessible to the cpu) outw( 0x0100, TSEQ_PORT ); // enter synchronous reset outw( 0x0302, TSEQ_PORT ); // write to maps 0 and 1 outw( 0x0304, TSEQ_PORT ); // use odd-even addressing outw( 0x0300, TSEQ_PORT ); // leave synchronous reset outw( 0x0004, GRAF_PORT ); // select map 0 for reads outw( 0x1005, GRAF_PORT ); // enable odd-even addressing outw( 0x0E06, GRAF_PORT ); // map starts at 0xB800:0000 } void map_device_memory( int base, int size ) { int fd = open( "/dev/mem", O_RDWR ); if ( fd < 0 ) { perror( "/dev/mem" ); exit(1); } int prot = PROT_READ | PROT_WRITE; int flag = MAP_FIXED | MAP_SHARED; void *mm = (void*)base; if ( mmap( mm, size, prot, flag, fd, base ) == MAP_FAILED ) { perror( "mmap" ); exit(1); } }