mem_offset()

I am trying to translate from virtual addresses to physical addresses. First
of all, I noticed that the QRTP has the call posix_mem_offset() instead of
mem_offset in the documentation but posix_mem_offset() return ENOSYS.
Anyway, I can still call mem_offset() successfully. However, I have a
question about the contig_len parameter. According to the documentation,

Upon return, the value pointed to by contig_len is either length, or the
length of the largest contiguous block of typed memory that’s currently
mapped to the calling process starting at addr, whichever is smaller.

In my case, I seem to be getting “whichever is larger”.

This is my test program, called MemOffset.cpp. The idea is to translate a
single contiguous buffer in virtual address space into its underlying list
of memory segments in physical address space.

#include
#include
#include
#include <unistd.h>
#include
#include <sys/types.h>
#include <sys/mman.h>

int main(int argc, char **argv)
{
int length = atoi(argv[1]);
// char *buffer = new char[length];
char *buffer = (char *)malloc(length);
char *buf = buffer;
off_t offset;
size_t contigLen;
do {
if (mem_offset(buf, NOFD, length, &offset, &contigLen) == -1) {
cerr << "mem_offset() failed: " << strerror(errno) << endl;
return 1;
}
cout << "virtual: " << (void *)buf << endl;
cout << "length: " << length << endl;
cout << "physical: " << (void *)offset << endl;
cout << "contig length: " << contigLen << endl << endl;
buf += contigLen;
length -= contigLen;
} while (length > 0);
return 0;
}

This is the program’s output.

./MemOffset 1

virtual: 0x804d68c
length: 1
physical: 0x619568c
contig length: 2420

./MemOffset 10000

virtual: 0x804af3c
length: 10000
physical: 0x6192f3c
contig length: 196

virtual: 0x804b000
length: 9804
physical: 0x6193000
contig length: 4096

virtual: 0x804c000
length: 5708
physical: 0x6194000
contig length: 4096

virtual: 0x804d000
length: 1612
physical: 0x6195000
contig length: 4096

The second example of translating a 10000 byte buffer is easier to
understand. The first 196 bytes in virtual space corresponds to the last 196
bytes of physical page 0x6192000. Then we have 2 full physical pages of 4096
bytes (0x6193000 and 0x6194000). Then the last 1612 bytes in virtual space
corresponds to the first 1612 bytes of physical page 0x6195000.

Now, why is the last “contig length” 4096 instead of 1612? By definition, it
should return the smaller one, which is 1612.

Secondly, this virtual buffer seems to be contiguous in physical address
space as well as virtual address space. Why doesn’t mem_offset() simply
returns contig length of 10000 on the first call?

-Kim

Kim Liu <kliu@terayon.com> wrote:

I am trying to translate from virtual addresses to physical addresses. First
of all, I noticed that the QRTP has the call posix_mem_offset() instead of
mem_offset in the documentation but posix_mem_offset() return ENOSYS.
Anyway, I can still call mem_offset() successfully.

mem_offset() was removed from the QNX RTP documentation because it didn’t make
it to the IEEE Approved Draft 10 standard (it had been defined in 1003.1j Draft 5)
It’s been replaced by posix_mem_offset(). It still exists (but most likely
not very well supported) for upwards compatibility (i.e. from Neutrino 2.1).

I’ll let a developer step in now…


However, I have a
question about the contig_len parameter. According to the documentation,

Upon return, the value pointed to by contig_len is either length, or the
length of the largest contiguous block of typed memory that’s currently
mapped to the calling process starting at addr, whichever is smaller.

In my case, I seem to be getting “whichever is larger”.

This is my test program, called MemOffset.cpp. The idea is to translate a
single contiguous buffer in virtual address space into its underlying list
of memory segments in physical address space.

#include <cstdlib
#include <iostream
#include <cstring
#include <unistd.h
#include <cerrno
#include <sys/types.h
#include <sys/mman.h

int main(int argc, char **argv)
{
int length = atoi(argv[1]);
// char *buffer = new char[length];
char *buffer = (char *)malloc(length);
char *buf = buffer;
off_t offset;
size_t contigLen;
do {
if (mem_offset(buf, NOFD, length, &offset, &contigLen) == -1) {
cerr << "mem_offset() failed: " << strerror(errno) << endl;
return 1;
}
cout << "virtual: " << (void *)buf << endl;
cout << "length: " << length << endl;
cout << "physical: " << (void *)offset << endl;
cout << "contig length: " << contigLen << endl << endl;
buf += contigLen;
length -= contigLen;
} while (length > 0);
return 0;
}

This is the program’s output.

./MemOffset 1

virtual: 0x804d68c
length: 1
physical: 0x619568c
contig length: 2420

./MemOffset 10000

virtual: 0x804af3c
length: 10000
physical: 0x6192f3c
contig length: 196

virtual: 0x804b000
length: 9804
physical: 0x6193000
contig length: 4096

virtual: 0x804c000
length: 5708
physical: 0x6194000
contig length: 4096

virtual: 0x804d000
length: 1612
physical: 0x6195000
contig length: 4096

The second example of translating a 10000 byte buffer is easier to
understand. The first 196 bytes in virtual space corresponds to the last 196
bytes of physical page 0x6192000. Then we have 2 full physical pages of 4096
bytes (0x6193000 and 0x6194000). Then the last 1612 bytes in virtual space
corresponds to the first 1612 bytes of physical page 0x6195000.

Now, why is the last “contig length” 4096 instead of 1612? By definition, it
should return the smaller one, which is 1612.

Secondly, this virtual buffer seems to be contiguous in physical address
space as well as virtual address space. Why doesn’t mem_offset() simply
returns contig length of 10000 on the first call?

-Kim

Thank God. I thought nobody’s going to reply to this post.

Just want to say that I am still eager to get an answer from a developer.

-Kim