Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате
Форум программистов > C/C++: Программирование под Unix/Linux > vm86


Автор: wladF 6.11.2010, 17:38
Привет, есть задача исполнить 16 битный код, прерывания биоса и т.п. в Линуксе.
Получится ли правильно слинковать 32-битный код гцц с 16-битной реализацией асмвоской ф-и, которая будет находиться в отдельном файле ?
Т.е. имеем следующее
Код

.code16
.section .text
.globl int10h
.type int10h, @function
.align 16
int10h:
    xor %ax, %ax
    int $0x10
...

и C файл, в котором ф-я int10h используется вызовом vm86
сборка:
gcc main.c main.s

Автор: bsa 12.11.2010, 23:43
wladF, даже если и получится слинковать, работать все равно не будет. Так как операция int вызовет исключение общей защиты, что будет отработано ядром и послан сигнал SIGSEGV твоей проге.
Если хочешь запускать подобный код используй dosbox. Нативно в современных ОС это делать нельзя.

Автор: wladF 13.11.2010, 12:37
Т.е. прерывания не получится использовать в режиме эмуляции 8086? для которого существует сис. вызов vm86.

Автор: bsa 13.11.2010, 13:19
Код
#include <stdio.h>        // for printf(), perror() 
#include <fcntl.h>        // for open() 
#include <stdlib.h>        // for exit() 
#include <unistd.h>        // for lseek(), read() 
#include <sys/mman.h>        // for mmap()
#include <asm/vm86.h>        // for struct vm86_struct
#include <linux/linkage.h>    // 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" );
}
Код взят отсюда: http://www.linux.org.ru/forum/development/1517294#comment-1517991
Человек говорит, что программа в любом случае завершается сегфолтом.

Powered by Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)