www.delorie.com/archives/browse.cgi   search  
Mail Archives: djgpp/1995/12/13/17:04:41

Date: Wed, 13 Dec 95 15:55:32 GMT
From: Neil Jarvis <Neil DOT Jarvis AT proteon DOT com>
To: djgpp AT sun DOT soe DOT clarkson DOT edu
Cc: antwerp AT tpd DOT tno DOT nl
Subject: Re: Getting the physical address of allocated virtual memory
Reply-To: Neil DOT Jarvis AT proteon DOT com

Well I've managed to solve my own problem, and I thought the knowledge
may be useful to the other DJGPPers out there.

The problem was that I required the ability to allocate virtual memory in
the 1Mb to 16Mb range, to lock this area into physical memory, and to be
able to get hold of the physical memory address of the region
allocated. The physical address was then given to DMA controllers on PC
adapter cards, allowing both the application and the adapter cards to
access the region.

The solution I took was to approach the problem in the reverse
direction. If I could allocate some memory above 1Mb for which I know the
address, and then I should be able to get DPMI to map a linear address
onto this area, in the same way that memory-mapped devices can be
accessed by a linear address.

To allocate the memory, I call XMS to both allocate and lock a region of
memory. This memory will be above 1Mb, and XMS kindly returns the
physical address of this new region. 

I then call __dpmi_physical_address_mapping to create the linear address
mapped to the physical region. 

Creating and initialising an LDT with this linear address now allows the
application to access the XMS allocated memory using the functions in
<sys/farptr.h>.

I hacked together a program to verify this approach, and tested it using
DJGPP-V2-Beta3 and CWSDPMI-Beta8. It works!

I've included the short program source code at the end of this mail, to
help any others struggling with this type of memory/virtual/physical
address problem.

Enjoy!

-- Neil Jarvis, Proteon International, York R&D (Neil DOT Jarvis AT proteon DOT com)
--  "Energize" said Kirk, and the pink bunny appeared.



#include <stdio.h>
#include <string.h>
#include <dpmi.h>
#include <go32.h>
#include <sys/farptr.h>

#define BLOCK_SIZE 2*1024

void dpmi_error(unsigned short code)
{
   switch (code)
   {
   case 0x8001:
      printf("DPMI Error: unsupported function (16-bit host)\n");
      break;
   case 0x8003:
      printf("DPMI Error: system integrity (invalid device address)\n");
      break;
   case 0x8012:
      printf("DPMI Error: linear memory unavailable\n");
      break;
   case 0x8013:
      printf("DPMI Error: physical memory unavailable\n");
      break;
   case 0x8014:
      printf("DPMI Error: backing store unavailable\n");
      break;
   case 0x8016:
      printf("DPMI Error: handle unavailable\n");
      break;
   case 0x8021:
      printf("DPMI Error: invalid value (ECX = 0)\n");
      break;
   case 0x8023:
      printf("DPMI Error: Invalid handle\n");
      break;
   case 0x8025:
      printf("DPMI Error: invalid linear address (EBX not page aligned)\n");
      break;
   default:
      printf("DPMI Error: Unknown code %04X\n", code);
      break;
   }
}

void xms_error(unsigned char code)
{
   switch (code)
   {
   case 0x80:
      printf("XMS Error: Function not implemented\n");
      break;
   case 0x81:
      printf("XMS Error: VDISK detected\n");
      break;
   case 0xA0:
      printf("XMS Error: All available extended memory is allocated\n");
      break;
   case 0xA1:
      printf("XMS Error: All available extended memory handles are in use\n");
      break;
   case 0xA2:
      printf("XMS Error: Handle is invalid\n");
      break;
   case 0xAA:
      printf("XMS Error: Block is not locked\n");
      break;
   case 0xAB:
      printf("XMS Error: Handle is locked\n");
      break;
   case 0xAC:
      printf("XMS Error: The block's lock count overflows\n");
      break;
   case 0xAD:
      printf("XMS Error: Lock failed\n");
      break;
   default:
      printf("XMS Error: Unknown code %02X\n", code);
      break;
   }
}
   
int main()
{
   unsigned short xms_cs, xms_ip, block_handle;
   unsigned long physaddr, linearaddr;
   unsigned short xms_memory;
   __dpmi_meminfo meminfo;
   __dpmi_regs regs;

   /* Check for XMS present */
   bzero(&regs, sizeof(regs));
   regs.x.ax = 0x4300;
   __dpmi_simulate_real_mode_interrupt(0x2f, &regs);
   if ((regs.x.ax & 0x00ff) != 0x0080)
   {
      printf("XMS not present. Error code = %04X\n", regs.x.ax);
      return 1;
   }

   /* Get entry point */
   bzero(&regs, sizeof(regs));
   regs.x.ax = 0x4310;
   __dpmi_simulate_real_mode_interrupt(0x2f, &regs);
   printf("Entry point = %X:%X\n", xms_cs = regs.x.es, xms_ip = regs.x.bx);

   /* Get version */
   bzero(&regs, sizeof(regs));
   regs.x.cs = xms_cs;
   regs.x.ip = xms_ip;
   regs.x.ax = 0x0000;
   __dpmi_simulate_real_mode_procedure_retf(&regs);
   printf("XMS vesion = %d.%d\n", regs.x.ax >> 8, regs.x.ax & 0x00ff);

   /* Allocate block of memory */
   bzero(&regs, sizeof(regs));
   regs.x.cs = xms_cs;
   regs.x.ip = xms_ip;
   regs.x.ax = 0x0900;
   regs.x.dx = 2 * 1024;
   __dpmi_simulate_real_mode_procedure_retf(&regs);
   if (regs.x.ax != 0x0001)
   {
      printf("Failed to allocate %dk block of XMS\n", BLOCK_SIZE);
      xms_error(regs.x.bx & 0x00ff);
      return 2;
   }
   else
      printf("Handle of %dk block = %04X\n", BLOCK_SIZE, block_handle = regs.x.dx);

   /* Lock block of memory */
   bzero(&regs, sizeof(regs));
   regs.x.cs = xms_cs;
   regs.x.ip = xms_ip;
   regs.x.ax = 0x0c00;
   regs.x.dx = block_handle;
   __dpmi_simulate_real_mode_procedure_retf(&regs);
   if (regs.x.ax != 0x0001)
   {
      printf("Failed to lock %dk block of XMS\n", BLOCK_SIZE);
      xms_error(regs.x.bx & 0x00ff);
      return 2;
   }
   else
   {
      physaddr = (unsigned long) regs.x.dx << 16 | (unsigned long) regs.x.bx;
      printf("Locked %dk block at physical location %08lX\n", BLOCK_SIZE, physaddr);
   }
   
   /* Map linear address to  XMS memory */
   meminfo.size=BLOCK_SIZE * 1024;
   meminfo.address=physaddr;
   if(__dpmi_physical_address_mapping(&meminfo) == -1)
   {
      printf("Physical mapping of address 0x%08lX failed!\n",physaddr);
      dpmi_error(__dpmi_error);
      goto undoxms;
   }
   linearaddr = meminfo.address;

   /* Now setup an LDT descriptor */
   xms_memory = __dpmi_allocate_ldt_descriptors(1);
   __dpmi_set_segment_base_address(xms_memory, linearaddr);
   __dpmi_set_segment_limit(xms_memory, (BLOCK_SIZE*1024)|0xfff);

   printf("Linear address = %08lX, physical address = %08lX\n", linearaddr, physaddr);

   /*
   ** We now have a 2MB region of XMS memory allocated above 1Mb, it is
   ** locked, we have its physical address to give to the adapter's DMA
   ** controllers, and its linear address to allow the application to access
   ** the region using <sys/farptr.h> calls.
   */

   /* Run a wee test on the memory */
   {
      unsigned long i;

      printf("Writing to memory area\n");
      for (i = 0; i < (BLOCK_SIZE * 1024L) / 4L; i++)
      {
	 /* Write a LONG */
	 _farpokel(xms_memory, i*4, i);
      }
      printf("Verifying memory area\n");
      for (i = 0; i < (BLOCK_SIZE * 1024L) / 4L; i++)
      {
	 unsigned long r = _farpeekl(xms_memory, i*4);
	 if (r != i)
	 {
	    printf("Failure @ %08lX, expected data = %08lX, actual data = %08lX\n", i, i, r);
	    goto undoxms;
	 }
      }
   }
   
undoxms:

   /* Unlock block of memory */
   bzero(&regs, sizeof(regs));
   regs.x.cs = xms_cs;
   regs.x.ip = xms_ip;
   regs.x.ax = 0x0d00;
   regs.x.dx = block_handle;
   __dpmi_simulate_real_mode_procedure_retf(&regs);
   if (regs.x.ax != 0x0001)
   {
      printf("Failed to unlock %dk block of XMS\n", BLOCK_SIZE);
      xms_error(regs.x.bx & 0x00ff);
      return 2;
   }
   else
      printf("Unlocked %dk block\n", BLOCK_SIZE);
   
   /* Free block */
   bzero(&regs, sizeof(regs));
   regs.x.cs = xms_cs;
   regs.x.ip = xms_ip;
   regs.x.ax = 0x0a00;
   regs.x.dx = block_handle;
   __dpmi_simulate_real_mode_procedure_retf(&regs);
   if (regs.x.ax != 0x0001)
   {
      printf("Failed to free %dk block of XMS\n", BLOCK_SIZE);
      xms_error(regs.x.bx & 0x00ff);
      return 2;
   }
   else
      printf("Freed %dk block\n", BLOCK_SIZE);

   return 0;
}

- Raw text -


  webmaster     delorie software   privacy  
  Copyright © 2019   by DJ Delorie     Updated Jul 2019