Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

dos buffer

34 views
Skip to first unread message

Eric

unread,
Apr 18, 2006, 10:31:15 PM4/18/06
to
Can anyone point me to some sample code that shows how to allocate a dos
buffer (below 1 meg). I want to understand how to do things this way and
not rely on tb.
For instance:
allocate buffer below 1 meg - size -32k
fill buffer with data and read it back
store actual buffer address in say regs.r.ax and regs.r.bx
free buffer

I looked at __dpmi_allocate_dos_memory but it gets you a selector and I dont
know what to do to convert that to a pointer

Thanks
Eric

DJ Delorie

unread,
Apr 18, 2006, 10:49:06 PM4/18/06
to dj...@delorie.com

> I looked at __dpmi_allocate_dos_memory but it gets you a selector
> and I dont know what to do to convert that to a pointer

You do exactly what you do with the tb - either use farptr/nearptr, or
dosmemput/dosmemget.

DOS memory is *not* part of your regular memory, you can't just
"convert" such selectors to pointers. You have to go through the same
tricks to switch from the virtual memory your program uses to the
physical memory DOS uses, both for the transfer buffer and for any
other DOS memory you allocate (low memory, high memory, or XMS
memory).

Rod Pemberton

unread,
Apr 19, 2006, 9:01:28 PM4/19/06
to

"Eric" <No...@invalid.com> wrote in message
news:A8adnbpWz9FuPdjZ...@comcast.com...

Now, the memory below 1Mb is physically mapped per the DPMI specification,
but a buffer in that region still needs to be allocated. Unfortunately, DOS
memory must be allocated through the DPMI host and not directly through DOS
itself. It handles some other issues and allocates from DOS. Therefore, to
allocate DOS memory, you must use either one of these:

1) __dpmi_allocate_dos_memory
2) _go32_dpmi_allocate_dos_memory

Now, _go32_dpmi_allocate_dos_memory() uses segments and offsets through a
structure, like you want. However, I'm not fond of the _go32_xxx functions
because the set of functions is incomplete. So, you end up spending all
your time reformating segments, offsets, etc. to switch between the _go32
functions and _dpmi functions...

Anyway, I've written two examples. They both compile cleanly, but haven't
been thoroughly tested (i.e., possible bugs...). If there are any bugs,
you'll need to sort them out yourself.

Method 1)
----
#include <dpmi.h>
#include <go32.h>
#include <sys/farptr.h>

#define BUFF 32768
int main(void)
{
unsigned long base;
/* unsigned short segment,offset; */
int selector;
char buf[BUFF];

/* base is the physical address of the low mem buffer */
/* selector is used for virtual addressing, i.e., within application space
*/
__dpmi_allocate_dos_memory((BUFF+15)>>4,&selector);
__dpmi_get_segment_base_address(selector,&base);

#if 0
/* this is how to calculate segment & offset, if needed */
segment=(unsigned long)base>>4;
offset=(unsigned long)base&0x0F;
#endif

dosmemput(buf, BUFF, base); /* copy to low mem */
/* something done to low mem buffer: DOS call, farpoke */
_farpokeb(selector,12,0x20); /* set low mem buf[12] to 0x20 */
dosmemget(base, BUFF, buf); /* copy from low mem */
__dpmi_free_dos_memory(selector);

return(0);
}

Method 2)
----
#include <string.h>
#include <dpmi.h>
#include <go32.h>
#include <sys/farptr.h>
#include <sys/nearptr.h>

#define BUFF 32768
int main(void)
{
unsigned long base,CS_base;
/* unsigned short segment,offset; */
int selector;
unsigned char buf[BUFF];
unsigned char *bufl;

/* base is the physical address of the low mem buffer */
/* selector is used for virtual addressing, i.e., within application space
*/
__dpmi_allocate_dos_memory((BUFF+15)>>4,&selector);
__dpmi_get_segment_base_address(selector,&base);

/* get the physical starting address of the code segment */
/* and enable full address range */
__dpmi_get_segment_base_address(_my_cs(),&CS_base);
__djgpp_nearptr_enable();

#if 0
for physical-to-virtual addressing use: (e.g., screen=0xB8000)
#ifdef __DJGPP__
"variable" -=CS_base;
#endif
for virtual-to-physical addressing use: (e.g., lgdt,lidt,etc.)
#ifdef __DJGPP__
"variable" +=CS_base;
#endif
#endif

bufl=(unsigned char *)base; /* create a pointer to low mem */
bufl+=CS_base; /* convert virtual to physical address */

#if 0
/* this is how to calculate segment & offset, if needed */
segment=(unsigned long)bufl>>4;
offset=(unsigned long)bufl&0x0F;
#endif

memcpy(bufl,buf,BUFF); /* copy to low mem */
/* something done to low mem buffer: DOS call, farpoke */
_farpokeb(selector,12,0x20); /* set low mem buf[12] to 0x20 */
memcpy(buf,bufl,BUFF); /* copy from low mem */
__dpmi_free_dos_memory(selector);

return(0);
}


HTH,

Rod Pemberton


A. Wik

unread,
Apr 20, 2006, 6:15:19 AM4/20/06
to
On Wed, 19 Apr 2006, Rod Pemberton wrote:

>
> Anyway, I've written two examples. They both compile cleanly, but haven't
> been thoroughly tested (i.e., possible bugs...). If there are any bugs,
> you'll need to sort them out yourself.
>
> Method 1)
> ----
> #include <dpmi.h>
> #include <go32.h>
> #include <sys/farptr.h>
>
> #define BUFF 32768
> int main(void)
> {
> unsigned long base;
> /* unsigned short segment,offset; */
> int selector;
> char buf[BUFF];
>
> /* base is the physical address of the low mem buffer */
> /* selector is used for virtual addressing, i.e., within application space
> */
> __dpmi_allocate_dos_memory((BUFF+15)>>4,&selector);
> __dpmi_get_segment_base_address(selector,&base);

Some nit-picking regarding terminology:

"physical" = The primitive, most low-level form of address from
a system software (privileged) point of view, and
which in the good old days referred to an address
output by the CPU onto the bus for referencing main
memory, hardware registers (memory mapped IO), the
video BIOS, RAM buffers on SCSI/EMS/Ethernet cards,
and so on (or non-existent address space). In this
day and age, references to "physical" addresses
usually never leave the chip (instead landing on
the cache). Various CPUs are capable of generating
20-, 24-, 32-, 36-, 40-bit physical addresses or
some other size.

"logical" = The address formed (explicitly or implicitly) by a
16-bit segment + a 16-, 32-, or 64-bit offset, all
depending CPU type and mode. Translated into a
linear address through the classical "SHL 4 & ADD"-
scheme, or starting from the 286 in protected mode,
via the descriptor cache initialised from the GDT
and optional LDT table(s) upon loading a segment
register.

"linear" = The 0-based address space derived from a logical
address. From the 8086-80286, and on 386+ in the
absence of paging, physical addresses are formed
directly by copying/extending/truncating the linear
address. With paging enabled on the 386+,
translation into physical is instead done according
to the page tables, configurable in an ever
increasing numbers of ways. At least one of those
ways must be sizeable enough to cover the CPU's
physical addressing capabilities (or the latter
would be rather pointless), however awkward it may
be to implement and use (e.g. 36-bit addressing,
for using more than 4 GB RAM on 32-bit CPUs would
require a scheme of swapping physical memory in and
out of the address space, much like the classical
16-bit DOS technologies: EMS, bank-switching,
overlays...).

"flat" = The memory management scheme in which the code-,
stack- and data-segments are all set up with a
base address of 0 and a limit including all the
memory the program is intended reference.

"virtual" = Linear address not equal to the physical address
by sign/zero-extension. Might even be swapped
out to disk.

.. (Corrections/additions welcome.)


The __dpmi_physical_address_mapping() function can be used to
request a virtual address (range) mapped to a specific physical
address, such as the linear frame buffer for a SVGA graphics
mode - sample code (error checking omitted):

__dpmi_meminfo dmemi;
unsigned sel;
int st; /* status of calls */

dmemi.size = xres * yres * bpp + 4093 & ~4093;
dmemi.address = lfb_addr;
st = __dpmi_physical_address_mapping(&dmemi);

sel = __dpmi_allocate_ldt_descriptors(1);
st = __dpmi_set_segment_base_address(sel, dmemi.address);
st = __dpmi_set_segment_limit(sel, dmemi.size-1);

-aw

Eric

unread,
Apr 20, 2006, 6:39:40 PM4/20/06
to
Rod Pemberton wrote:

Hey! Thanks a lot, that helped immensely!
Now i have something i can work with.
Thanks again,
Eric

Rod Pemberton

unread,
Apr 20, 2006, 9:48:54 PM4/20/06
to

"A. Wik" <a...@aw.gs> wrote in message
news:2006042003...@dynamite.narpes.com...

That's a bit different than the way I use those terms. I usually use
'virtual' for EIP address since it's relative to the base address of the CS
selector. I usually use physical for a base 0, flat address space or what
is the closest thing to the hardware lines...

> The __dpmi_physical_address_mapping() function can be used to
> request a virtual address (range) mapped to a specific physical
> address, such as the linear frame buffer for a SVGA graphics
> mode - sample code (error checking omitted):
>
> __dpmi_meminfo dmemi;
> unsigned sel;
> int st; /* status of calls */
>
> dmemi.size = xres * yres * bpp + 4093 & ~4093;
> dmemi.address = lfb_addr;
> st = __dpmi_physical_address_mapping(&dmemi);
>
> sel = __dpmi_allocate_ldt_descriptors(1);
> st = __dpmi_set_segment_base_address(sel, dmemi.address);
> st = __dpmi_set_segment_limit(sel, dmemi.size-1);
>

Just remember that the DPMI host has already mapped memory below 1Mb (or is
it 1Mb+64k?). So, you shouldn't pass addresses below 1Mb to
__dpmi_physical_address_mapping. This will cause failures with certain DPMI
hosts. Also, the Charles Sandmann based DPMI hosts (CWSDPMI, and CWSDPR0)
have a hardcoded physical address limit of 128Mb.

You only need two selectors for DJGPP, both of which are provided _dos_ds
and _my_ds() (and/or _my_cs()). The limit of _dos_ds can be extended to 4Gb
with __dpmi_set_segment_limit, providing a base 0, flat or linear address
space. But, you must use non-standard functions like _far/nearptr.
_my_ds() can also be extended to 4Gb (except under Windows), but it's base
address is set by the DPMI host. This allows a full 4Gb address space (with
32-bit wraparound), and standard C pointers. But, the pointers need to be
adjusted for the base address... If you want a non-segmented programming
environment, i.e., true base 0, flat or linear address space, OpenWatcom
compiles that way.


Rod Pemberton


DJ Delorie

unread,
Apr 20, 2006, 10:40:33 PM4/20/06
to dj...@delorie.com

For DJGPP's purposes, consider these definitions wrt how they're
translated:

virtual -> segment table -> linear -> page table -> physical -> RAM chips

A virtual address may or may not represent a linear address (it won't,
for example, if the selector has an invalid value, or if the segment
table has a special entry in it, or if the address is beyond the end
of the segment.

A linear address may or may not represent a physical address depending
on whether or not the page table has a "present" entry for that page.
Non-present pages may be stored on disk.

A physical address may or may not map to physical RAM chips, depending
on how much memory you have ;-)

alex bodnaru

unread,
Apr 21, 2006, 1:44:02 AM4/21/06
to dj...@delorie.com
look fo "btrieve" in the mailing list

alex

0 new messages