Device driver entry points accessing - linux-kernel

Can different entry points in a function be accessed by other drivers?
I know that by using EXPORT_SYMBOL we can do it for functions and symbols. My confusion is can read/write entry points be exported. If I do so will be against good driver practice?

You can export any Global function and Variable using EXPORT_SYMBOL() even device file operations read() and write() too. It will be very difficult to call them from any kernel modules because of the parameters required to call them for example file pointer of the device.

Related

Definition of "trace_gpio_value" function in linux kernel

I'm reading the gpiolib.c code in the linux kernel to understand how the GPIO driver works. But I didn't find any definition of "trace_gpio_value" function.
trace_gpio_value(desc_to_gpio(desc), 0, value);
Anybody can help me about definition of trace_gpio_value?
trace_gpio_value() and generally trace_*() are used by kernel ftrace static tracing utility to monitor some internals such as GPIO or networking (used for debugging and other purposes). These static tracing points cause collected data to be stored in a kernel buffer which you can see it's internals from tracing virtual file system mounted at /sys/kernel/tracing if Kconfig option CONFIG_FTRACE=y. So, in a nutshell these trace points will act as a hook to call other tracing functions that you provide.
About the actual definition and how they work you must declare your tracing point using DECLARE_TRACE() in your header file. In your case check include/trace/events/gpio.h where you specify your tracing function and how it will work:
#include <linux/tracepoint.h>
# note the NAME (first_parameter)
TRACE_EVENT(gpio_value,
...<SNIP...>
);
NOTE: TRACE_EVENT() is a macro that gets expanded to DECLARE_TRACE().
Then in your C code file you will add trace_gpio_value() whenever you want to trace and get the gpio_value() being called or another functions for another purposes.

How to call a function defined in a kernel module from a user space program

I have created one kernel module. within the module i have defined some functions say function1(int n) and function2().
There was no error in compiling and inserting the module. What i don't understand is how to call the function1(n) and function2() from a user space program.
I think there is no direct way to do it, you can't link userspace code with the kernel like you do with a library. First, you have to register your function as syscall and then call the syscall with the syscall() function.
See here
Also some interface between kernel and user space possible using socket communication see
this link
And find use full link related to this topic at right side of page.
You can make your driver to react on writes to a /dev/file file or a /proc/file file.
EDIT
Form name file my point is device is as file in kernel and you can access via ioctl()
the pretty good explanation is http://tldp.org/LDP/lkmpg/2.6/html/lkmpg.html#AEN885
See Link

How linux drive many network cards with the same driver?

I am learning linux network driver recently, and I wonder that if I have many network cards in same type on my board, how does the kernel drive them? Does the kernel need to load the same driver many times? I think it's not possible, insmod won't do that, so how can I make all same kind cards work at same time?
regards
The state of every card (I/O addresses, IRQs, ...) is stored into a driver-specific structure that is passed (directly or indirectly) to every entry point of the driver which can this way differenciate the cards. That way the very same code can control different cards (which means that yes, the kernel only keeps one instance of a driver's module no matter the number of devices it controls).
For instance, have a look at drivers/video/backlight/platform_lcd.c, which is a very simple LCD power driver. It contains a structure called platform_lcd that is private to this file and stores the state of the LCD (whether it is powered, and whether it is suspended). One instance of this structure is allocated in the probe function of the driver through kzalloc - that is, one per LCD device - and stored into the platform device representing the LCD using platform_set_drvdata. The instance that has been allocated for this device is then fetched back at the beginning of all other driver functions so that it knows which instance it is working on:
struct platform_lcd *plcd = to_our_lcd(lcd);
to_our_lcd expands to lcd_get_data which itself expands to dev_get_drvdata (a counterpart of platform_set_drvdata) if you look at include/linux/lcd.h. The function can then know the state of the device is has been invoked for.
This is a very simple example, and the platform_lcd driver does not directly control any device (this is deferred to a function pointer in the platform data), but add hardware-specific parameters (IRQ, I/O base, etc.) and you get how 99% of the drivers in Linux work.
The driver code is only loaded once, but it allocates a separate context structure for each card. Typically you will see a struct pci_driver with a .probe function pointer. The probe function is called once for each card by the PCI support code, and it calls alloc_etherdev to allocate a network interface with space for whatever private context it needs.

win32k.sys mapping address in the session space

My question:
when win32k.sys is loaded into the session space, does it get the same base address in every session?
Details:
I'm writing a kernel-mode device driver for Windows (32 bit). It loads as a standard WDM driver into the system space (global kernel-mode memory) during the system boot.
However in some situations I need to access functions exported by win32k.sys. To be exact, I'm writing a sort of a driver that needs sometimes to pretend as a display driver.
I may not statically import those functions (means, import them via executable import table). This is because win32k.sys is loaded during the later stage when sessions are created. Moreover, it's loaded into the session space.
Nevertheless I've found the workaround. During the session creation I import the needed functions dynamically. I use ZwQuerySystemInformation with SystemModuleInformation to find the base address of win32k.sys in the current session. Then using this base address I analyze it to find the export directory of win32k.sys and obtain the needed function pointers.
Currently for every session I keep a separate array of imported functions. However practically those functions are always the same in all the sessions. Means - win32k.sys is mapped into the same address belonging to the session space in every session.
Hence, my question is, is there a guarantee that win32k.sys will be mapped into the same address in all the sessions?
Apart from saving some memory this will make things easier for me. Currently in order to call such a function I need a session-specific context where the function pointers are stored.
My experience is that win32k.sys base address is the same in the context of all processes the driver is mapped. During its initialization, win32k.sys calls ntoskrnl.exe to create Object Type kernel objects for desktops, window stations and possibly other objects used by the driver. These kernel objects must be at the same addresses in context of all processes to keep the kernel data structures consistent (for example, there is an array of pointers to all Object Type objects inside ntoskrnl.exe module).
Moreover, win32k.sys contains a system call table (win32k!W32pServiceTable). Address of the table is, again, stored in a fixed location in ntoskrnl.exe (nt!KeServiceDescriptorTableshadow).
So, if the win32k.sys driver was mapped to different addresses in different session, ntoskrnl.exe must behave the same. And this is not true (such behavior would cause additional problems, for example, with SYSENTER/SYSCALL). But I did not see this fact written in any official documentation.
I am not very sure but I guess the answer is YES. Win32k.sys is just another (special) dll file, and every dll file on Windows has a base address in its PE header. For win32k.sys which is provided by the Windows(I think), the base address should never conflict with other system dll (.sys) files.
To be safe, you can make your program a little bit flexible. At the beginning, you assume the address is same. But you check the address before you actually call it. In that way, the system will not hang because of bad address, at least.

Accesing block device from kernel module

I am interested in developing kernel module that binds two block devices into a new block device in such manner that first block device contains data at mount time, and the other is considered empty. Every write is being made to second partition, so on next mount the base filesystem remains unchanged. I know of solutions like UnionFS, but those are filesystem-based, while i want to develop it a layer lower, block-based.
Can anyone tell me how could i open ad read/write block device from kernel module? Possibly without using userspace program for reading/writing merged block devices. I found similar topic here, but the answer was rather unsatysfying because filp_* functions are rather for reading small config files, not for (large) block device I/O.
Since interface for creating block devices is standarized i was thinking of direct (or almost direct) acces to functions implementing source devices, as i will be requested to export similar functions anyway. If i could do that i would simply create some proxy-functions calling appropriate functions on source devices. Can i somehow obtain pointer to a gendisk structure that belongs to different driver?
This serves only my own purposes (satisfying quriosity being main of them) so i am not worried about messing my kernel up seriously.
Or does somebody know if module like that already exists?
The source code in the device mapper driver will suit your needs. Look at the code in the Linux source in Linux/drivers/md/dm-*.
You don't need to access the other device's gendisk structure, but rather its request queue. You can prepare I/O requests and push it down the other device's queue, and it will do the rest itself.
I have implemented a simple block device that opens another block device. Take a look in my post describing it:
stackbd: Stacking a block device over another block device
Here are some examples of functions that you need for accessing another device's gendisk.
The way to open another block device using its path ("/dev/"):
struct block_device *bdev_raw = lookup_bdev(dev_path);
printk("Opened %s\n", dev_path);
if (IS_ERR(bdev_raw))
{
printk("stackbd: error opening raw device <%lu>\n", PTR_ERR(bdev_raw));
return NULL;
}
if (!bdget(bdev_raw->bd_dev))
{
printk("stackbd: error bdget()\n");
return NULL;
}
if (blkdev_get(bdev_raw, STACKBD_BDEV_MODE, &stackbd))
{
printk("stackbd: error blkdev_get()\n");
bdput(bdev_raw);
return NULL;
}
The simplest example of passing an I/O request from one device to another is by remapping it without modifying it. Notice in the following code that the bi_bdev entry is modified with a different device. One can also modify the block address (*bi_sector) and the data itself.
static void stackbd_io_fn(struct bio *bio)
{
bio->bi_bdev = stackbd.bdev_raw;
trace_block_bio_remap(bdev_get_queue(stackbd.bdev_raw), bio,
bio->bi_bdev->bd_dev, bio->bi_sector);
/* No need to call bio_endio() */
generic_make_request(bio);
}
Consider examining the code for the dm / md block devices in drivers/md - these existing drivers create a block device that stores data on other block devices.
In fact, you could probably implement your idea as another "RAID personality" in md, and thereby make use of the existing userspace tools for setting up the devices.
You know, if you're a GPL'd kernel module you can just call open(), read(), write(), etc. from kernel mode right?
Of course this way has certain caveats including requiring forking from kernel mode to create a space for your handle to live.

Resources