Guia de Desenvolvimento para Executar Programas Linux em Ambiente DOS

O projeto doslinux permite a execução de binários Linux dentro de um sistema DOS. Este guia explora os detalhes de implementação do processo de inicialização e da simulação de chamadas de sistema que tornam isso possível.

Sequência de Inicialização

A inicialização configura o ambiente raiz necessário. O ponto de entrada é a função main() no arquivo init/init.c.

Preparação do Sistema de Arquivos

Primeiramente, o sistema de arquivos raiz é remontado em modo leitura-escrita com sincronização, garantindo que as escritas do Linux sejam visíveis no DOS:

if (mount(NULL, "/", "vfat", MS_REMOUNT | MS_SYNCHRONOUS, NULL)) {
    perror_fatal("Erro ao remontar raiz");
}

Em seguida, um sistema de arquivos temporário (ramfs) é criado e montado, e o sistema de arquivos virtual proc é configurado:

if (mount(NULL, "/mnt/doslinux_root", "ramfs", 0, NULL)) {
    perror_fatal("Erro ao montar ramfs");
}

// Montagem do /proc
if (mkdir("/mnt/doslinux_root/proc", 0755) || 
    mount(NULL, "/mnt/doslinux_root/proc", "proc", 0, NULL)) {
    perror_fatal("Falha ao configurar /proc");
}

Instalação de Ferramentas Básicas

O utilitário BusyBox é copiado para a nova hierarquia de diretórios, e links simbólicos são criados para os comandos comuns:

copiar_arquivo("/bin/busybox", "/mnt/doslinux_root/bin/busybox");
criar_diretorios_essenciais("/mnt/doslinux_root"); // Cria /bin, /sbin, etc.
instalar_applets_busybox();

Criação de Nós de Dispositivo

Nós de disposiitvo essenciais são criados para permitir o acesso a hardware básico:

mknod("/mnt/doslinux_root/dev/mem", S_IFCHR | 0600, makedev(1, 1));
mknod("/mnt/doslinux_root/dev/tty", S_IFCHR | 0600, makedev(5, 0));

Troca do Sistema de Arquivos Raiz

Por fim, o sistema muda para o novo ambiente de raiz usando a chamada de sistema pivot_root:

if (syscall(SYS_pivot_root, "/mnt/doslinux_root", "/mnt/doslinux_root/old_root")) {
    perror_fatal("Falha na troca de raiz (pivot_root)");
}

Simulação de Chamadas de Sistema

O núcleo do doslinux é um emulador de chamadas de sistema Linux. A lógica central reside no manipulador handle_syscall() dentro de init/vm86.c.

Dispatching de Chamadas

O manipulador examina o registrador AH para determinar a operação solicitada:

void handle_syscall(cpu_state_t *cpu) {
    uint8_t syscall_num = (cpu->eax >> 8) & 0xFF;

    switch(syscall_num) {
        case SYS_NUM_EXEC:
            execute_program(cpu);
            break;
        case SYS_NUM_GETPID:
            cpu->eax = get_simulated_pid();
            break;
        // ... outros handlers ...
        default:
            cpu->eax = -ENOSYS; // Não implementado
    }
}

Execução de Programas

A operação de execução extrai o comando do segmento de memória do programa e o delega ao interpretador de comandos:

case SYS_NUM_EXEC: {
    uint16_t segment = cpu->cs;
    uint8_t *program_segment = (uint8_t*)(segment << 4);
    uint8_t cmd_length = program_segment[0x80];
    char command[256];
    memcpy(command, &program_segment[0x81], cmd_length);
    command[cmd_length] = '\0';
    int result = shell_execute(command);
    cpu->eax = result;
    break;
}

Entrada no Modo Virtual 8086 (VM86)

Para executar o código DOS real, o sistema entra no modo VM86. A configuração e o controle deste modo são feitos via uma chamada de sistema especializada:

void iniciar_monitor_virtual(vm86_config_t *config) {
    // Mapeia a memória baixa necessária
    void *mem_dos = mmap(NULL, DOS_MEMORY_SIZE, PROT_READ | PROT_WRITE | PROT_EXEC,
                         MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
    // Configura a estrutura de estado do VM86
    inicializar_estado_vm86(config, mem_dos);
    // Entra no loop de emulação
    int status = syscall(SYS_vm86, VM86_ENTER, config);
    if (status < 0) {
        perror("Erro na emulação VM86");
    }
}

Gerenciamento de Tarefas Simuladas

Após a inicialização, o processo primário cria processos filhos para isolar o shell de controle do monitor de máquina virtual.

int main(int argc, char *argv[]) {
    inicializar_ambiente();

    pid_t pid_shell = fork();
    if (pid_shell == 0) {
        executar_shell_interativo();
        exit(EXIT_FAILURE);
    }

    pid_t pid_vmmon = fork();
    if (pid_vmmon == 0) {
        vm86_config_t config;
        configurar_vm86(&config);
        iniciar_monitor_virtual(&config);
        exit(EXIT_FAILURE);
    }

    // Processo pai aguarda a finalização dos filhos
    while (wait(NULL) > 0);
    return 0;
}

Tags: doslinux systemcalls vm86 dos linuxcompatibility

Publicado em 6-7 20:14 por Thomas