Subject: Re: how to write codes to access memory start at address 0xF1000000
To: Randy Wenjiun Lin <rblim@aht.com>
From: John F. Woods <jfw@jfwhome.funhouse.com>
List: current-users
Date: 09/03/1997 19:39:02
> > I am doing embedded system programming on Netbsd 
> > I need to access data on a shared memory which start at 0xF1000000. 
> > How to write codes to have the data on the shared memory accessed? 
> > In other words, how to make an array start at address 0xF100000? I want
> > to declare an array  containing all the adresses to which I can access
> > those data pointed. Any ideas?

> This should be standard C. :-)

Aaaaargh!  It's statements like this that make me wish I was a postal worker.

> Basically you want to have a variable be a pointer to the array at
> 0xF100000. I.E. you have some data structure (maybe a struct, maybe not)
> which matches the data format you expect at 0xF100000. You have a variable
> which is a pointer to such a structure. You set the pointer to 0xF100000
> (with a type cast in there probably). You then de-reference the pointer.

Given that this person is doing embedded programming on NetBSD, and not
embedded programming without an operating system, I assume that he wants
to address some kind of shared memory at 0xF1000000 in some address space
OTHER than user virtual address space, which is what a USER PROCESS
containing

	char *p = (char *)0xF1000000;

is going to try (and fail) to address.

Now, depending on the hardware in question, "0xF1000000" could be an address
on a physical memory bus, any one of several I/O busses, or even "processor
control space" (68K family).  I will GUESS that the hardware in question is
an x86-pc-based embedded control system (which now predominates due to its
unique unsuitability to embedded control), and further that this is
0xF1000000 in physical bus address space.

	If the shared memory is on a PCI bus, I think the intervention of
	a device driver is required in order to establish a physical address
	for the PCI address.  (I suspect that the mapping is one-to-one on
	the x86, i.e. a PCI address of 0xF1000000 will become a physical
	address of 0xF1000000, but you still need to set up the page table
	entries.)  [Someone please correct me if I'm wrong.]

	If the shared memory is on a VLB card, I think the VL bus just passes
	physical addresses to cards and hopes one acknowledges (or
	double-resets the processor if you have a defective motherboard like
	mine... :-( ).

	If the shared memory is on an ISA card, then it ain't at 0xF1000000
	unless you're presupposing a virtual mapping for it!  (This would have
	to be set up by a driver.)

To share memory on NetBSD, a user process uses the mmap() system call.
Because the address space of interest is physical bus addresses (rather than
the blocks of a file, or kernel virtual address space), the file you want
to give to mmap() is /dev/mem (which you'll need to open() first).

So, assuming that the shared memory is actually responding to physical
addresses starting at 0xF1000000 (see the PCI discussion above) and 4096
bytes long (you'll see how to correct that), a user process would do
something like

	/* remember to #include the correct headers! */
	int mem = open("/dev/mem", O_RDWR);

	/* check for open failure */

	char *region = mmap((caddr_t)0, (size_t)4096, PROT_READ|PROT_WRITE,
			    MAP_FILE /* see below */,
			    mem,
			    (off_t)0xF1000000);

This will return some wholly arbitrary user virtual address (NOT necessarily
0xF1000000!!) which is mapped to a physical address of 0xF1000000.

The mmap() page mentions two flags that might be worth or'ing in with MAP_FILE
(alas, it doesn't describe them in enough detail to know whether they're
actually useful or not in this case): MAP_HASSEMAPHORE (just what IS "special
handling"???) and MAP_SHARED (I assume the "shared memory" is shared with
other processORS rather than other user processES, but I suspect this flag
is intended to disable copy-on-write -- which you certainly don't want if
the underlying thing being addressed isn't plain, vanilla kernel-managed
RAM!).

There's a lot of details left out, and maybe some errors added, but I think
this is enough to provide a start (and a hint of what kernel modules to start
reading ("Use the Source, Luke!")), and I don't have time to research a
complete answer.  It is, at least, more correct than just "stick 0xF1000000
in a pointer variable and off you go".  (Off into the weeds, more like it.)