Domanda

Si prega di perdonare i miei tentativi di necromanzia, ma in realtà ho bisogno di scrivere del codice per DOS a 16 bit (!). Devo verificare che un pezzo di software esegue correttamente quando costruito per una piattaforma a 16 bit, e ho scoperto che le nostre stazioni di lavoro di XP possono effettivamente funzionare a 16 bit applicazioni DOS, che permette di utilizzare il sistema di test batch esistente.

In ogni caso, il software è composto da una biblioteca e un database. database più piccoli (fino a ~ 150 kB) possono sia essere definiti come un array globale statico o lette da file in un buffer allocato con halloc(), quindi sono abbastanza fiducioso che lo strumento biblioteca e di test è costruito in modo corretto.

Tuttavia, abbiamo anche alcune banche dati più grandi per prova, fino a ~ 1.8Mb. Questo è troppo grande per allocare normalmente, così ho scritto una piccola libreria di supporto per allocare la memoria XMS. Con questo, posso allocare con successo, l'uso (vale a dire di scrittura e lettura dei dati) e gratis fino a 16 Mb di dati in un piccolo programma giocattolo. Tuttavia, quando si utilizzano i servizi XMS nell'applicazione "reale", ottengo il seguente errore:

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

Googling su questo errore ha dato risultati poco rilevanti, questo tipo di errore sembra essere di solito la colpa su di malware vari.

Il codice di base è severo C90, il compilatore attualmente utilizzata per DOS costruisce è OpenWatcom 1.9 utilizzando il "grande" modello di memoria. Non ci sono avvisi o errori durante la costruzione.

La libreria di supporto XMS segue, l'errore sembra si verifica dopo la chiamata a 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);
}

Alcune domande concrete:

  1. Dove posso trovare ulteriori informazioni sul messaggio di errore (immagino mezzi OP codice operativo, ma per quanto riguarda gli altri campi?)
  2. Il riferimento API XMS ho trovato ancora si applica quando in esecuzione su Windows XP, o c'è qualche nuova versione dovrei fare riferimento?
  3. Potrei avvitata dello stato del sistema con l'assemblatore inline? Come devo risolvere questo?
  4. Avete un'idea migliore su come risolvere questo problema? :-) estensori DOS sembrano richiedere modalità a 32 bit, l'intero punto di questo esercizio utilizza la modalità a 16 bit.
È stato utile?

Soluzione 2

Ack, devo rispondere alla mia domanda.

Mentre è possibile per allocare relativamente grandi quantità di memoria che utilizzano le routine XMS, non è possibile esprimere il indirizzo con i 16 bit. Il valore di ritorno è un 32-bit lineari indirizzo, e se ho capito correttamente semplicemente non è possibile utilizzare tale da un ambiente a 16 bit.

dovrebbe essere possibile utilizzare tale blocco di memoria mappando una parte a qualche buffer di memoria locale di sotto del limite indirizzabile 1Mb e spostare la finestra, molto simile a come funziona SME, ma che è semplicemente non ne vale la pena.

Altri suggerimenti

vedo due problemi.

1 °: Assicurarsi che il compilatore utilizza un gran lunga chiamata invece di una chiamata nei pressi altrimenti si passa al segmento sbagliato ed eseguire codice sconosciuto e la generazione di un codice operativo non valido possably ... che è quello che sembra accadere. Prova "chiamata lontano [XMSControl]" nel codice, se il compilatore default è vicino chiamate.

2 °: NTVDM.EXE esegue codice in modalità virtuale 86 e non è vero modalità reale. Se è vero che Windows XP supporta 16 applicazioni bit, ha un supporto limitato. Si può incorrere in altri problemi con il database lungo la linea a causa di questo. Per esempio non sarà in grado di accedere USB, quindi non è possibile stampare su una stampante USB e sarà necessario utilizzare una vecchia stampante stile porta parallela. Buona fortuna findign uno di quelli usati in un garage vendita ...

'0f 04 10 0e 51' è un'istruzione non valida in sé si sta tentando di eseguire.

Ho controllato, e non vedo di istruzioni x86 con questo codice 0F 04

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

Quindi è necessario trovare quale codice di generare tali un'istruzione non valida e risolverlo.

Per quanto riguarda la memoria, ho sempre pensato che lo SME è più facile da usare rispetto XMS, ma potrei sbagliarmi.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top