gpt4 book ai didi

c - 16 位 DOS 中的 XMS 分配

转载 作者:行者123 更新时间:2023-12-04 11:58:44 24 4
gpt4 key购买 nike

请原谅我的死灵法术尝试,但实际上我需要为 16 位 DOS (!) 编写一些代码。我必须验证一个软件在为 16 位平台构建时是否正确执行,我发现我们的 XP 工作站实际上可以运行 16 位 DOS 应用程序,这使得使用现有的批测试系统成为可能。

无论如何,软件都是由一个库和一个数据库组成的。较小的数据库(最多 ~150kB)可以定义为静态全局数组或从文件读取到使用 halloc() 分配的缓冲区,因此我非常有信心构建库和测试工具正确。

但是,我们也有一些更大的数据库需要测试,高达 ~1.8Mb。这对于正常分配来说太大了,所以我写了一个小的支持库来分配 XMS 内存。有了这个,我可以在一个小玩具程序中成功分配、使用(即写入和读取数据)和释放多达 16Mb 的数据。但是,在“真实”应用程序中使用 XMS 工具时,出现以下错误:

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

谷歌搜索此错误几乎没有相关结果,此类错误似乎通常归咎于各种恶意软件。

代码库是严格的 C90,当前用于 DOS 构建的编译器是使用“大”内存模型的 OpenWatcom 1.9。构建时没有警告或错误。

XMS 支持库如下,错误似乎发生在调用 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);
}

一些具体问题:

  1. 我在哪里可以找到有关错误消息的更多信息(我猜 OP 是指操作码,但其他字段呢?)
  2. 我发现的 XMS API 引用在 Windows XP 上运行时是否仍然适用,或者是否有一些更新的版本我应该引用?
  3. 我可以用内联汇编程序搞砸系统状态吗?我该如何解决?
  4. 对于如何解决这个问题,您有更好的想法吗? :-) DOS 扩展程序似乎需要 32 位模式,本练习的重点是使用 16 位模式。

最佳答案

我看到两个问题。

第 1 步:确保您的编译器使用的是远调用而不是近调用,否则您将跳转到错误的段并执行未知代码,并可能生成无效的操作码……这似乎是正在发生的事情。如果您的编译器默认为近调用,请尝试在您的代码中“调用远 [XMSControl]”。

第二:NTVDM.EXE 在虚拟 86 模式下运行代码,而不是真正的实模式。虽然 Windows XP 确实支持 16 位应用程序,但它的支持有限。因此,您可能会遇到数据库的其他问题。例如,您将无法访问 USB,因此您无法在 USB 打印机上打印,需要使用旧的并口打印机。祝你好运,找到一个在旧货拍卖会上使用过的...

关于c - 16 位 DOS 中的 XMS 分配,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/4323622/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com