Click to See Complete Forum and Search --> : ISA Device Drivers In User Space


CuongTran
09-15-2001, 01:22 PM
I'm new to Linux, but I need to write a program that can read the memory map of the ISA bus. I have Red Hat 7.1 with the 2.4.2-2 kernel. From reading here http://www.xml.com/ldd/chapter/book/ch02.html#t7
I think I can write a device driver in user space. So I go here http://www.xml.com/ldd/chapter/book/ch08.html#t6
and it tells me how to do it. I can't find the <linux/io.h> file, though.

So I try writing a simple program like so
#include <linux/version.h>
#include <linux/kernel.h>
#include <asm/system.h>
#include <asm/io.h>
#include <linux/ioport.h>
#include <stdio.h>
#include <linux/module.h>
#include <linux/fs.h>

#define MemoryAddress 0xA0000

int main(void)
{
int MemoryVariable;
MemoryVariable = isa_readb (MemoryAddress);
return 0;
}
but I get some sort of linking problem. I compile it with this command
"gcc filename.c"

Can anyone help me? I know that writing a program to read the memory address has to be really easy, but I can't get it to work. Thanks.

LittleGreenGecko
09-15-2001, 03:42 PM
How would you do this in windows?

I was just wondering if you can show me, then the difference may be implied.

pinoy
09-15-2001, 05:26 PM
How about:


/* -- try.c -- */
#include <asm/io.h>
#include <stdio.h>

#define MEM_ADDR 0xa000

int main(void)
{
int mem_var = 0;
mem_var = isa_readb(MEM_ADDR);
printf("mem_var = 0x%08x\n", mem_var);
return 0;
}


Compile with:

gcc -o try try.c -D__KERNEL__

CuongTran
09-16-2001, 01:01 PM
I'm not sure how to do that in windows. And I tried that code and tried to compile it and it gives me a lot more linking errors. Is there a file I'm suppose to link it to?

pinoy
09-16-2001, 05:49 PM
Compile with -D__KERNEL__?

CuongTran
09-16-2001, 07:25 PM
yup. I tried it with that compile command. WIthout that command, I just get undefined refrence. But with that command, I get a long list of errors. It works for you?

pinoy
09-16-2001, 08:29 PM
yes. I'll have to check what kernel I run at home. I think it's a 2.4

CuongTran
09-17-2001, 09:54 AM
ok, at my computer at work, when I try the code with that compile command, I get undefine refrence to '__io_virt_debug' colect 2: ld returned 1 exit status.

So I try compiling it with gcc -o try try.c -D__KERNEL__ -D__io_virt_debug and I get a bunch of errors.
io.lh:117: parse error before '1'
io.h: In function 'check_signature':
io.h:223 calling object is not a function
io.h: In function 'isa_check_signature':
io.h:39: calling object is not a function
try.c:7: called object is not a function.

and line 7 is the one with the isa readb command.

sans-hubris
09-17-2001, 11:41 AM
Originally posted by CuongTran:
<STRONG>ok, at my computer at work, when I try the code with that compile command, I get undefine refrence to '__io_virt_debug' colect 2: ld returned 1 exit status.

So I try compiling it with gcc -o try try.c -D__KERNEL__ -D__io_virt_debug and I get a bunch of errors.
io.lh:117: parse error before '1'
io.h: In function 'check_signature':
io.h:223 calling object is not a function
io.h: In function 'isa_check_signature':
io.h:39: calling object is not a function
try.c:7: called object is not a function.

and line 7 is the one with the isa readb command.</STRONG>

You either want to have the kernel headers in /usr/include or change the &lt;&gt;s with quotation marks (except for stdio.h of course) and add -I/usr/src/linux/include/ (replace /usr/src/linux with the source directory for your kernel, if you don't have the kernel source code, get it here (http://www.kernel.org).)

CuongTran
09-17-2001, 04:28 PM
I tried to replace the include path and it still gives me the same error, but if I make a module for linux, I *think* it works right. I still don't know why it won't work in user space. Here is what I did.

*************
#define __KERNEL__
#define MODULE
#include &lt;linux/module.h&gt;
#include &lt;asm/io.h&gt;

int init_module(void)
{
printk("&lt;1&gt;%x", isa_readb(0xA0000));
printk("\n");
return 0;
}

void cleanup_module(void)
{
printk("&lt;1&gt;Exiting\n");
}
***********
then I compiled it with
"gcc -c try.c"
ran it with
"insmod try.o"
and removed it with
"rmmod try"

but it won't work if I try to make it an executable.
What version of linux are you using and which package? I'm using Redhat 7.1 with kernel 2.4.2-2

Thanks for the help.

pinoy
09-18-2001, 04:51 AM
After grepping through the source, io_virt_debug is nothing but some simple sanity checking.

&lt;asm/io.h&gt; also nulls it out if CONFIG_DEBUG_IOVIRT is not set.

So try compiling with:

cc -o try try.c -D__KERNEL__ -UCONFIG_DEBUG_IOVIRT

If that doesn't work, NULL it out with:

#define io_virt_debug(a,b,c)((void*)a)

If that still doesn't work, open up "src/linux/arch/i386/lib/iodebug.c", copy the function and delete the printks.

augur
09-18-2001, 05:51 AM
Greetings,

I could be wrong about this and please correct me if i am, but i don't think you can run kernel code in user space. Kernel code is suposed to run at ring0, where it has unrestricted access to the hardware. Even if you could compile an executable out of it, you'd run into all sorts of "faults" due to the x86 protection mechanism. User space programs, or applications, run in ring3, where it is confined to it's own, isolated, memory space and has no direct access to hardware. Communication with hardware, in user space, is done through request to device drivers, wich run at kernel level.
It is, however, possible to map and access memory outside you memory space, and to request direct access to certain I/O ports and communicate directly to hardware this way. This is done with the functions "mmap" and "ioperm" and you have to run the program as root.

Hope this helps.

pinoy
09-18-2001, 06:47 AM
augur, that's true. The ISA address space is fortunately memory mapped. If you try and follow isa_readb(addr) source, it eventually resolves into a pointer indirection of (PAGE_OFFSET + addr).

CuongTran, if these all fails, here's a version of isa_readb (Note: not tested)


#define PAGE_OFFSET 0xc0000000
#define ISA_BASE ((unsigned char*)PAGE_OFFSET)
#define isa_readb2(addr) (*(volatile unsigned char *)(ISA_BASE+(addr)))

sans-hubris
09-18-2001, 08:24 AM
Originally posted by pinoy:
<STRONG>After grepping through the source, io_virt_debug is nothing but some simple sanity checking.

&lt;asm/io.h&gt; also nulls it out if CONFIG_DEBUG_IOVIRT is not set.

So try compiling with:

cc -o try try.c -D__KERNEL__ -UCONFIG_DEBUG_IOVIRT

If that doesn't work, NULL it out with:

#define io_virt_debug(a,b,c)((void*)a)

If that still doesn't work, open up "src/linux/arch/i386/lib/iodebug.c", copy the function and delete the printks.</STRONG>
Modules are supposed to be compiled as objects, so don't link them (i.e. use the -c option.) This relates back to what augur was talking about (I think) and this is why you cannot link them. When you do an insmod or a modprobe the module object is linked to the kernel itself (I believe) and that is how it gets unrestricted access.

CuongTran
09-18-2001, 10:06 AM
The writer of this book http://www.xml.com/ldd/chapter/book/ch02.html#t7
says I can do things in user space, I think. It's not too clear to me, though.

When I run this command to compile
gcc -o try try.c -D__KERNEL__ -UCONFIG_DEBUG_IOVIRT
I get the same undefine refrence to '__io_virt_debug' error.

When I add
#define __io_virt_debug(a,b,c)((void*)a)

I get
/usr/include/asm/io.h: 117: parse error before void.
and this line in io.h it is
entern void *__io_virt_debug(unsigned long x, const char *file, int line);

When I copy the source of iodebug.c and add it to the program and remove the printk command, the program compiles, but it just hangs when it reaches the isa_readb command.

Finally, when I add
#define PAGE_OFFSET 0xc0000000
#define ISA_BASE ((unsigned char*)PAGE_OFFSET)
#define isa_readb2(addr) (*(volatile unsigned char *)(ISA_BASE+(addr)))
the program also just hangs when I get to the isa_readb2 command.

If I can't get this thing to run totally in user space, I'll need to figure out how to pass the values of the isa_readb command from the module to the program. Basically I just need to read data off an ISA bus and append it to a file.

Thanks

pinoy
09-18-2001, 05:41 PM
Unfortunately my hardware knowledge is very rusty. I'll have a look at some of my hardware books at home tonight, and see if I can get anything from the ISA address space.

augur
09-19-2001, 05:03 AM
Greetings,

pinoy:
The ISA address space is fortunately memory mapped. If you try and follow isa_readb(addr) source, it eventually resolves into a pointer indirection of (PAGE_OFFSET + addr).
Yes, but is it mapped into YOUR application memory space?
Doesn't this have to be done at run time?
I dont think you can just accesss memory 0xc0000000 like that! Once you mmap it it would be ok.

Muad Dib --formerly ndogg, yes modules are linked to the kernel itself, there are no libraries to link it to.


CuongTran:
Finally, when I add
#define PAGE_OFFSET 0xc0000000
#define ISA_BASE ((unsigned char*)PAGE_OFFSET)
#define isa_readb2(addr) (*(volatile unsigned char *)(ISA_BASE+(addr)))
the program also just hangs when I get to the isa_readb2 command.

If I can't get this thing to run totally in user space, I'll need to figure out how to pass the values of the isa_readb command from the module to the program. Basically I just need to read data off an ISA bus and append it to a file.
It hangs because the memory you are trying to access is not mapped into your space.

Check this page on mmap (http://www.opengroup.org/onlinepubs/7908799/xsh/mmap.html).
It should be something like this:
#include &lt;sys/mman.h&gt;
int main() {
int file;
unsigned char *address;

file = open("/dev/mem");
address = mmap(0, &lt;length&gt;, PROT_READ, MAP_SHARED, file, &lt;offset&gt; /*0xc0000000 ?*/);
/* now just use the memory as you normally would */
}
I haven't tested this, im not at my linux box, my motherboard died this weekend! But i think it should work. You have to be root to run this.

pinoy
09-19-2001, 06:24 AM
You're probably right augur. I've only looked at the kernel source quickly, and I haven't found my hardware book to see what kind of information I get. The kernel probably does not map the area automatically to user space. I only tried compiling the above program and once I got that to run noticed that it blocked. I guessed it must be waiting for some data. I also assumed that since it blocked the isa address space must have been mapped in user space. You can't block on a pointer indirection otherwise! You'd get a segfault.


It hangs because the memory you are trying to access is not mapped into your space.

It shouldn't hang. This is why I just assumed that the isa address space must have been mapped into user space. It's very unusual to block on a pointer indirection. You usually only block on IO.


Muad Dib --formerly ndogg, yes modules are linked to the kernel itself, there are no libraries to link it to.


You will notice, that Cuongtran did actually make an object file, managed to compile, load and unload it.

Then again, it is probably a bad idea compiling with -D__KERNEL__ anyway. This suggests that you will be run in kernel space. Or the so called ring0 in intel platforms.

CuongTran
09-19-2001, 12:47 PM
I tried this:


#include &lt;asm/io.h&gt;
#include &lt;sys/mman.h&gt;
int main(void)
{
int file;
int temp = 0;
unsigned char *address;
file = open("/dev/mem");
address = mmap(0, 1, PROT_READ, MEM_SHARED, file, 0xC1000);
printf(" the memory here is\n");
while (temp &lt;= 0x0F)
{
printf("%x", *(address+temp));
temp++;
}
printf("\nending\n");
return 0;
}


Running this code, it spit out the same hex numbers whien I made the module with isa_readb(0xC1000) command and "insmod" the object file.

Does this mean instead of using isa_readb() in userspace, I just mmap and read it off there?

augur
09-20-2001, 05:42 AM
Originally posted by CuongTran:
Does this mean instead of using isa_readb() in userspace, I just mmap and read it off there?

Greetings,

Yes, i think that in userspace that is the safest and easiest way to go.

CuongTran
09-20-2001, 10:20 AM
Ok, so I can ready from the ISA bus in user space, but now I can't write to it. It gives me a segmentation fault.


#include &lt;asm/io.h&gt;
#include &lt;sys/mman.h&gt;

int main(void)
{
int file;
unsigned char *address;
file = open("/dev/mem");
address = mmap(0, 0xFF, PROT_WRITE, MEM_SHARED, file, 0xD0000);
printf("running test write \n");
*(address) = 0xEE;
printf("\nending\n");
return 0;
}


How do I gain access so I can write to the memory?

augur
09-20-2001, 06:55 PM
Greetings,

Try changing the "PROT_WRITE" to "PROT_WRITE | PROT_READ".

CuongTran
09-20-2001, 08:33 PM
Ok, I FINALLY got it to read and write to the memory address! The problem was that with the file = open("/dev/mem") command, I had to allow write access to /dev/mem with O_RDWR. After that, it allowed me to read and write to memory easily. Thanks for all the help, I really appreciate it!


#include &lt;stdio.h&gt;
#include &lt;asm/io.h&gt;
#include &lt;sys/mman.h&gt;
#include &lt;stdlib.h&gt;
#include &lt;unistd.h&gt;
#include &lt;fcntl.h&gt;

int main(void)
{
int file;
unsigned long *address;
file = open("/dev/mem", O_RDWR, 0644);
printf ("\nfile = 0x%X\n", file);
address = mmap(0, 0xFFFF, PROT_READ|PROT_WRITE, MAP_SHARED|MAP_FIXED, file, 0xBF000);
printf("this is running\n");
printf("%x", *(address));
*(address) = 0x00;
printf("\nending\n");
return 0;
}