Question

S'il vous plaît pardonnez mes tentatives de nécromancie, mais je réellement besoin d'écrire du code pour DOS 16 bits (!). Je dois vérifier qu'un morceau d'exécutions logiciel correctement lorsque construit une plate-forme 16 bits, et j'ai découvert que nos postes de travail XP peuvent réellement fonctionner 16 bits applications DOS, qui permet d'utiliser le système de test de lot existant.

Dans tous les cas, le logiciel se compose d'une bibliothèque et une base de données. bases de données plus petites (jusqu'à ~ 150 ko) peuvent soit être définie comme un tableau global statique ou lire le fichier à un tampon alloué avec halloc(), donc je suis assez confiant que la bibliothèque et outil de test est construit correctement.

Cependant, nous avons aussi des grandes bases de données à tester, jusqu'à ~ 1.8Mb. Ceci est trop grand pour allouer normalement, j'ai donc écrit une petite bibliothèque de soutien pour allouer de la mémoire XMS. Avec cela, je peux attribuer avec succès, l'utilisation (par exemple écriture et de lecture des données) et gratuit jusqu'à 16 Mo de données dans un petit programme de jouet. Cependant, lors de l'utilisation des installations XMS dans l'application « réelle », je reçois l'erreur suivante:

The NTVDM CPU has encountered an illegal instruction.
CS:0000 IP:00ba OP:0f 04 10 0e 51

googler sur cette erreur a donné peu de résultats pertinents, ce type d'erreur semble être blâmé habituellement sur les logiciels malveillants divers.

Le code de base est C90 stricte, le compilateur actuellement utilisé pour DOS est construit OpenWatcom 1.9 en utilisant le modèle de mémoire « grande ». Aucun avertissement ou d'erreurs lors de la construction.

La bibliothèque suit de support XMS, l'erreur semble se produit après l'appel à xmsmalloc ():

/* This file implements rudimentary XMS memory handling.
 * Documentation on the XMS API was found on http://www.qzx.com/pc-gpe/xms30.txt
 */

#include <stddef.h> /* Definition of NULL */
#include <limits.h> /* Definition of UINT_MAX */
#include <stdio.h>  /* fprintf and (FILE *) */

/* Allow external configuration of maximum concurrent XMS allocations */
#ifndef MAX_XMS_ALLOCATIONS
#define MAX_XMS_ALLOCATIONS 4
#endif

/* Address of the XMS driver */
static long XMSControl;

/* Mapping of XMS handle <-> normal pointer */
typedef struct {
    unsigned int XMSHandle;
    void huge * XMSPointer; 
} XMSHandleMap;

static XMSHandleMap allocMap[MAX_XMS_ALLOCATIONS];

/* Set up the XMS driver, returns 0 on success and non-zero on failure */
static int initxms(void)
{
    char XMSStatus = 0;

    if ( XMSControl == 0 )
    {
        __asm {
        ; Is an XMS driver installed?
            mov ax,4300h
            int 2Fh
            mov [XMSStatus], al
        }

        if ( XMSStatus == 0x80 )
        {
            __asm {
            ; Get the address of the driver control function
                mov ax,4310h
                int 2Fh
                mov word ptr [XMSControl]  ,bx
                mov word ptr [XMSControl+2],es
            }
        }
    }

    return ( XMSControl == 0 );
}

/* Allocate a slab of memory from XMS */
void huge * xmsmalloc(long unsigned int size)
{
    unsigned int kB;
    unsigned int XMSStatus = 0;
    unsigned int XMSHandle = 0;
    void huge * XMSPointer = NULL;
    int n;

    /* If we can not initialize XMS, the allocation fails */
    if ( initxms() )
        return NULL;

    /* It is not possible to allocate more kilobytes than a 16-bit register can hold :-) */
    if ( size / 1024 > UINT_MAX )
        return NULL;

    /* Get the next free entry in the handle <-> pointer mapping */
    for ( n = 0; n < MAX_XMS_ALLOCATIONS; n++ )
    {
        if ( allocMap[n].XMSPointer == NULL )
            break;
    }

    if ( n == MAX_XMS_ALLOCATIONS )
        return NULL;

    kB = size / 1024 + (size % 1024 > 0);

    __asm {
    ; Allocate [kB] kilobytes of XMS memory
        mov ah, 09h
        mov dx, [kB]
        call [XMSControl]
        mov [XMSStatus], ax
        mov [XMSHandle], dx
    }

    /* Check if XMS allocation failed */
    if ( XMSStatus == 0)
        return NULL;

    __asm {
    ; Convert XMS handle to normal pointer
        mov ah, 0Ch
        mov dx, [XMSHandle]
        call [XMSControl]
        mov [XMSStatus], ax

        mov word ptr [XMSPointer],  bx 
        mov word ptr [XMSPointer+2],dx
    }

    if ( XMSStatus == 0 )
    {
        /* Lock failed, deallocate the handle */
        __asm {
        ; Free XMS handle
            mov ah, 0Ah
            mov dx, [XMSHandle]
            call [XMSControl]

        ; Return value is not really interesting 
        ;   mov [XMSStatus], ax
        }
        return NULL;
    }

    /* Create an entry in the handle <-> pointer mapping */
    allocMap[n].XMSHandle = XMSHandle;
    allocMap[n].XMSPointer = XMSPointer;

    return XMSPointer;
}

/* Free a pointer allocated with xmsalloc */
void xmsfree(void huge * XMSPointer)
{
    int n;

    if ( XMSPointer == NULL )
        return;

    if ( initxms() ) 
        return;

    for ( n = 0; n < MAX_XMS_ALLOCATIONS; n++ )
    {
        if ( allocMap[n].XMSPointer == XMSPointer )
        {
            int XMSHandle = allocMap[n].XMSHandle;

            __asm {
            ; Unlock handle so we can free the memory block
                mov ah, 0Dh
                mov dx, [XMSHandle]
                call [XMSControl]

            ; Free XMS memory
                mov ah, 0Ah
                mov dx, [XMSHandle]
                call [XMSControl]

            ; Return value ignored
            }

            /* Clear handle <-> pointer map entry so it can be reused */
            allocMap[n].XMSHandle = 0;
            allocMap[n].XMSPointer = NULL;

            return;
        }
    }
}

/* Write a memory report for debugging purposes */
void xmsreport(FILE * stream)
{
    int XMSVersionNumber = 0;
    int XMSLargestBlock = 0;
    int XMSTotal = 0;

    if ( initxms() ) 
    {
        puts("Could not initialize XMS Driver!");
        return;
    }

    __asm {
    ; Get the driver version number
        mov ah,00h
        call [XMSControl] ; Get XMS Version Number
        mov [XMSVersionNumber], ax

    ; Get the amount of free XMS memory
        mov ah, 08h
        call [XMSControl]
        mov [XMSLargestBlock], ax
        mov [XMSTotal], dx
    }

    fprintf(stream, "XMS Version number: %d\n", XMSVersionNumber);
    fprintf(stream, "Largest available block: %d kB (%d kB total)\n", XMSLargestBlock, XMSTotal);
}

Quelques questions concrètes:

  1. Où puis-je trouver plus d'informations sur le message d'erreur (je suppose que des moyens OP opcode, mais quid des autres domaines?)
  2. Est-ce que la référence API XMS je trouve toujours appliquer lors de l'exécution sous Windows XP, ou est-il une version plus récente je référence?
  3. Puis-je foiré l'état du système avec l'assembleur en ligne? Comment dois-je résoudre cela?
  4. Avez-vous une meilleure idée sur la façon de résoudre ce problème? :-) prolongateurs DOS semblent exiger le mode 32 bits, le point de cet exercice utilise le mode 16 bits.
Était-ce utile?

La solution 2

Ack, je dois répondre à ma propre question.

Bien qu'il soit possible de allouent des quantités relativement importantes de mémoire à l'aide des routines XMS, il est impossible de adresse il avec des instructions 16 bits. La valeur de retour est une adresse linéaire 32 bits, et si je l'ai bien compris correctement, il est tout simplement pas possible d'utiliser que d'un environnement 16 bits.

devrait est possible d'utiliser ce bloc de mémoire en traçant une partie de celui-ci à une mémoire tampon locale en dessous de la limite adressable 1Mb et déplacer la fenêtre, un peu comme la façon dont fonctionne EMS, mais qui est tout simplement pas la peine.

Autres conseils

Je vois deux problèmes.

1er: Assurez-vous que votre compilateur utilise un appel loin au lieu d'un appel près sinon vous sauter au segment mal et exécuter du code inconnu et générer possably un opcode non valide ... qui est ce qui semble se produire. Essayez « appeler loin [XMSControl] » dans votre code si vos paramètres par défaut du compilateur aux appels proximité.

2: NTVDM.EXE exécute le code en mode virtuel 86 et pas vrai mode réel. Il est vrai que Windows XP prend en charge 16 bits des applications, il a un soutien limité. Vous pouvez rencontrer d'autres problèmes avec votre base de données sur la ligne à cause de cela. Par exemple, vous ne pourrez pas USB d'accès, de sorte que vous ne pouvez pas imprimer sur une imprimante USB et vous devrez utiliser une ancienne imprimante de style port parallèle. Bonne chance un findign de ceux utilisés lors d'une vente de garage ...

'0f 04 10 0e 51' est instruction non valide lui-même que vous essayez d'exécuter.

Je l'ai vérifié, et je ne vois pas d'instructions x86 avec ce code 0F 04

http://ref.x86asm.net/geek.html#x0F04

Vous devez trouver quel code générer cette instruction non valide et le fixer.

En ce qui concerne la mémoire, je l'ai toujours pensé que l'EMS est plus facile à utiliser que XMS, mais je peux me tromper.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top