Mail Archives: djgpp/1996/05/03/12:37:09
dunder (dunder AT nyongwa DOT montreal DOT qc DOT ca) wrote:
: > Although this could be done, if you *absolutely* want it (look up the
: > 'nearptr' method in libc.inf and the FAQ list), it will cost you too
: > much to be really useful. The reason is that by doing this, you won't
: > necessarily drop out of protected mode (which you generally *can't* in
: > DJGPP), but you loose almost all the *protection* that way.
: I know, that's why I wanted another method ...
Another method is to use dpmi to map physical memory into your own
address-space. This is something I recently figured out and it's great. BUT...
it only works if cwsdpmi is providing the dpmi-services, it won't work with
Windows 95, it won't work with OS/2 (I haven't tested it with other dpmi
hosts).
The following example will try to map the video memory at a0000 in it's own
address-space, and fill a mode13 screen with all colors.
The map_physical_memory is copied from the library-sources, because I
couldn't get __dpmi_map_physical_memory to work (it wouldn't link, got
undefined symbol; if someone knows how to fix this, please tell me).
By the way, this is an edited non-tested version of the test-program I used,
so I wouldn't be surpised if it now contained some small typo's (I'm sorry for
that, but I don't have access to DJGPP right now).
#include <dos.h>
#include <go32.h>
#include <dpmi.h>
#include <errno.h>
#include <string.h>
/* Copyright (C) 1995 DJ Delorie, see COPYING.DJ for details */
#include <crt0.h>
#include <stddef.h>
/* Maps the specified number of bytes at a given address into our
* address space. All arguments must be page-aligned. Returns 0 on
* success, -1 on failure. This routine isn't as fast as it could be,
* but it shouldn't get called all that often.
*/
int map_physical_memory (void *_our_addr, unsigned long _num_bytes,
unsigned long _phys_addr)
{
unsigned long p, end;
/* Make sure all arguments are page aligned. */
if (((unsigned long) _our_addr & 0xfff )
|| (_phys_addr & 0xfff)
|| (_num_bytes & 0xfff))
{
errno = EINVAL;
printf("pages not aligned\n");
return -1;
}
/* Loop through the memory range, identify individual handles
* that intersect the range, and map the appropriate memory
* within each handle.
*/
for (p = (unsigned long) _our_addr, end = p + _num_bytes; p < end; )
{
const __djgpp_sbrk_handle *d;
unsigned long handle_end_addr;
__dpmi_meminfo meminfo;
/* Find the memory handle corresponding to the first byte. */
d = __djgpp_memory_handle (p);
if (d == NULL)
{
printf("d = __djgpp_memory_handler = NULL\n");
goto fail;
}
/* Find the last byte in the range that's also in the same
* memory handle as our current starting byte. We start with
* the farthest away address because it will usually be in the
* same memory handle, and we don't need to check any
* intermediate addresses once we know the far away address is
* in the same handle.
*/
for (handle_end_addr = end - 0x1000;
handle_end_addr > p;
handle_end_addr -= 0x1000)
{
const __djgpp_sbrk_handle *d2;
/* Find the memory handle corresponding to this test byte. */
d2 = __djgpp_memory_handle (handle_end_addr);
if (d2 == NULL)
{
printf("d2 = __djgpp_memory_handler = NULL\n");
goto fail;
}
/* Is this test byte in the same handle as the first byte? */
if (d2->handle == d->handle)
break;
}
handle_end_addr += 0x1000;
/* Map the appropriate physical addresses into this handle. */
meminfo.handle = d->handle;
meminfo.size = (handle_end_addr - p) / 0x1000; /* # pages */
meminfo.address = p - d->address;
if (__dpmi_map_device_in_memory_block (&meminfo,
(_phys_addr
+ (p - (unsigned) _our_addr))))
{
printf("__dpmi_map_device_in_memory_block failed\n");
goto fail;
}
/* Move on to the next memory handle. */
p = handle_end_addr;
}
/* success! */
printf("succes!\n");
return 0;
fail:
errno = EACCES;
return -1;
}
void mode13_enter()
{
/* set VGA-mode 13 */
union REGS in, out;
in.x.ax = 0x0013;
int86(0x10, &in, &out);
}
void mode13_leave()
{
/* set text-mode */
union REGS in, out;
in.x.ax = 0x0003;
int86(0x10, &in, &out);
}
char* ptr;
int main()
{
__dpmi_version_ret dvr;
int i;
int mapped = 0;
__dpmi_get_version(&dvr);
printf("major = %x, minor = %x\n", (int)dvr.major, (int)dvr.minor);
/* allocate a dummy-page, so we've got a pointer to somewhere in our
address-space */
ptr = malloc(65536);
if (map_physical_memory(ptr, 65536, 0xa0000) == -1)
printf("couldn't map physical memory (%s)\n", strerror(errno));
else
{
printf("physical memory mapped\n");
mapped = 1;
}
getchar();
if (mapped)
{
mode13_enter();
for (i = 0; i < 320*200; i++)
{
ptr[i] = i & 0xff;
}
getchar();
mode13_leave();
}
/* I guess it would be nicer to unmap the physical memory and to release
the dummy-page :) */
return 0;
}
Of course, this should also work with text-memory, just be sure to change the
'0xa0000' to '0xb8000' and always map a multiple of a complete page (4K, if
I'm not mistaking).
I hope this is of some use to people, please let me know if you got it to
work, I'm very interested to know. :)
DGreetings,
SAM
- Raw text -