Date: Wed, 13 Dec 95 15:55:32 GMT From: Neil Jarvis 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 . 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 #include #include #include #include #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(®s, sizeof(regs)); regs.x.ax = 0x4300; __dpmi_simulate_real_mode_interrupt(0x2f, ®s); if ((regs.x.ax & 0x00ff) != 0x0080) { printf("XMS not present. Error code = %04X\n", regs.x.ax); return 1; } /* Get entry point */ bzero(®s, sizeof(regs)); regs.x.ax = 0x4310; __dpmi_simulate_real_mode_interrupt(0x2f, ®s); printf("Entry point = %X:%X\n", xms_cs = regs.x.es, xms_ip = regs.x.bx); /* Get version */ bzero(®s, sizeof(regs)); regs.x.cs = xms_cs; regs.x.ip = xms_ip; regs.x.ax = 0x0000; __dpmi_simulate_real_mode_procedure_retf(®s); printf("XMS vesion = %d.%d\n", regs.x.ax >> 8, regs.x.ax & 0x00ff); /* Allocate block of memory */ bzero(®s, 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(®s); 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(®s, 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(®s); 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 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(®s, 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(®s); 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(®s, 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(®s); 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; }