//------------------------------------------------------------------- // vm86blue.cpp // // This short demo program shows the essential steps needed in // order for Linux to execute 16-bit code in Virtual-8086 Mode // (provided no "i/o-sensitive" instructions are encountered). // // This demo is intended to be run from the text-mode console; // no effect will be seen if executed from a graphics console. // // Since write-access to the '/dev/mem' special file is likely // restricted to privileged users, we recommend compiling this // program using: root# make vm86blue ; chmod a+s vm86blue // // NOTE: Written and tested using Linux kernel version 2.4.20. // // programmer: ALLAN CRUSE // written on: 18 JUL 2003 // revised on: 23 JUL 2003 -- to delete references to 'errno' //------------------------------------------------------------------- #include // for printf(), perror() #include // for open() #include // for exit() #include // for lseek(), read() #include // for mmap() #include // for struct vm86_struct #include // for asmlinkage attribute #define ELF_LOAD_ADDRESS 0x08048000 // where Linux puts this asmlinkage void blue( void ); // no C++ "name-mangling" asm(" .code16 "); // generate 16-bit codes asm(" .align 16 "); // "paragraph" alignment asm("blue: "); // label procedure entry asm(" movw $0xB800, %ax "); // address screen memory asm(" movw %ax, %es "); // using ES register asm(" xorw %di, %di "); // point es:di to screen asm(" movb $0x17, %al "); // white-upon-blue color asm(" movw $0x4000, %cx "); // number of screen elts asm("nxpel: "); // main loop begins here asm(" movb %al, %es:1(%di) "); // write color attribute asm(" addw $2, %di "); // point to next element asm(" loop nxpel "); // process entire screen asm(" hlt "); // exit Virtual8086 mode asm(" .code32 "); // generate 32-bit codes int vm86( struct vm86_struct *vm ) { int retval; asm(" movl $113, %eax "); // system-call ID-number asm(" movl %0, %%ebx " : : "m" (vm) ); // struct address asm(" int $0x80 "); // enter the Linux kernel asm(" movl %%eax, %0 " : "=m" (retval) ); // store retval return retval; // return function status } struct vm86_struct vm; // virtual machine struct int main( int argc, char **argv ) { int fd, prot, flag; // setup a memory-mapping for accessing video display memory void *vram = (void*)0x000B8000; // address of 32KB window prot = PROT_READ | PROT_WRITE; // read-write access is needed flag = MAP_FIXED | MAP_SHARED; // with a fixed-shared mapping if ( ( fd = open( "/dev/mem", O_RDWR ) ) < 0 ) { perror( "open /dev/mem" ); exit(1); } if ( mmap( vram, 0x8000, prot, flag, fd, (int)vram ) == MAP_FAILED ) { perror( "mmap /dev/mem" ); exit(1); } // setup 64KB memory-mapping for access to VM86 code and stack void *prog = (void*)0x00010000; // address of 64KB region prot = PROT_READ | PROT_WRITE; // read-write access is needed flag = MAP_FIXED | MAP_SHARED; // with a fixed-shared mapping if ( ( fd = open( "/dev/zero", O_RDWR ) ) < 0 ) { perror( "open /dev/zero" ); exit(1); } if ( mmap( prog, 0x10000, prot, flag, fd, 0 ) == MAP_FAILED ) { perror( "mmap /dev/zero" ); exit(1); } // now "load" our program code into this memory-mapped region if ( ( fd = open( argv[0], O_RDONLY ) ) < 0 ) { perror( argv[0] ); exit(1); } int progsize = lseek( fd, 0, SEEK_END ); if ( lseek( fd, 0, SEEK_SET ) != 0 ) { perror( "lseek" ); exit(1); } if ( read( fd, prog, progsize ) != progsize ) { perror( "read" ); exit(1); } // compute offset-address for the 16-bit code's entry-point int initial_IP = (int)blue - ELF_LOAD_ADDRESS; int initial_CS = ((int)prog) >> 4; // segment-address // initialize data-structure for entering to Virtual-8086 Mode vm.regs.eip = initial_IP; // initial instruction offset vm.regs.cs = initial_CS; // segment-address for code vm.regs.eflags = (1<<9); // IF=1, IOPL=0 vm.regs.ss = initial_CS; // segment-address for stack vm.regs.esp = 0x10000; // initial stacktop offset vm.cpu_type = CPU_386; // specify required processor // execute in Virtual-8086 Mode (until 'hlt' is encountered) vm86( &vm ); // execute the 'blue' routine printf( "\nReturned successfully from Virtual-8086 Mode\n\n" ); }