Questions about register_chrdev_region() in linux device driver - c

I'm learning about the registration of a kernel module using register_chrdev_region(dev_t from, unsigned count, const char * name);.
I notice that with or without this function, my kernel module worked as expected. The code I used for testing:
first = MKDEV(MAJOR_NUM, MINOR_NUM);
register_chrdev_region(first, count, DEVICE_NAME);//<---with and without
mycdev=cdev_alloc();
mycdev->ops= &fops;
mycdev->owner = THIS_MODULE;
if (cdev_add(mycdev,first, count) == 0)
{printk(KERN_ALERT "driver loaded\n");}
I commented out the line register_chrdev_region(first, count, DEVICE_NAME);, and the printk message still appeared. I tried to communicate with the driver with or without this from user space, and both are successful.
So my question is, is this function register_chrdev_region() only used to make my driver a good kernel citizen, just like telling the others that "I'm using up the major number, please don't use"?
I tried to have a look in the kernel source char_dev.c to understand the function, but I find it too difficult to understand, anyone that's familiar with this?
Thanks!

That will work because it's not actually necessary to allocate your device numbers up front. In fact, it's considered preferable by many kernel developers to use the dynamic (on-the-fly, as-needed) allocation function alloc_chrdev_region.
Whether you do it statically up front or dynamically as needed, it is something you should do to avoid conflict with other device drivers which may have played by the rules and been allocated the numbers you're trying to use. Even if your driver works perfectly well without it, that won't necessarily be true on every machine or at any time in the future.
The rules are there for a reason and, especially with low-level stuff, you are well advised to follow them.
See here for more details on the set-up process.

If the major number for your devices clash with any other device already in use, then the driver won't have the allocation done.
If you have already tested which major number is free and used it, it might generally not throw up an error and you will face no problem as u load the driver.
But if you run on various systems and if the major number is already captured and used by some other system., Then your driver loading can fail.
Its always better to use dynamic allocation !!

Related

How to handle changes to settings during runtime of a embedded c project?

I'm playing around with an esp32 (c with esp-idf, not with arduino) for a hobby project of mine. I'm currently programming a little drone that I can control with my smartphone. All works well.
But now I need to create system for persistent settings and parameters. For example pid-tuning parameters or what sensors are enabled and more. The general idea was to have a settings file in flash that is read on startup. The settings can then be used in the individual modules of the program. Now I'd also like to change those settings during runtime. For example pid tuning parameters. I don't want to reboot the system only to change a small parameter.
So now my question: How can I handle changes to those settings during runtime?
An idea was to have the module periodically ask a special
"settings-module" if there are any changes. It would then change its
internal settings accordingly. As settings shouldn't change that
often I think the overhead of constantly asking for updates is rather
unnecessary.
A more extreme idea was, to give a pointer to the variable in
question to the "settings-module". If any changes have to be made the
settings module would change the variable directly.
Or maybe a callback system?
The ideas seem feasible but I don't know if there are any best-practices or better options.
Does anyone of you know a name of a technique I can google or maybe an library that provides something similar?
Thanks!
ESP ISF already has 90% of your requirements covered with the non-volatile storage library - string keys, int/string values, wear levelling etc. Just use this to store all your settings and parameters. Read from it every time you want to get a value (unless you go to the sub-millisecond latency land, in which case it's perhaps best to cache the settings in RAM).
Reading a value from NVS can fail (e.g. if the parameter is not stored, the NVS partition got wiped, etc) which would introduce cumbersome error handling into every code block where you read a parameter. A common trick to avoid this error handling is to add a thin wrapper which takes a fallback value of the parameter and returns it every time reading the parameter from NVS fails. Something like this:
uint32_t fetchU32(const char* key, const uint32_t fallback) {
uint32_t ret;
if (ESP_OK != nvs_get_u32(g_nvs_hnd, key, &ret)) {
ret = fallback;
}
return ret;
}
Note that you need to be careful when using such wrappers - occasionally a critical parameter value must be found from NVS and not replaced with a fallback blindly.
Adding to what Tarmo suggested, you should also take not there are write limits to the ESP32's NVS. But do take note that the limits are set by what flash you are using.
I am placing this link where they discuss the write limits of the ESP32.

How feasible is it to virtualise the FILE* interfaces of C?

It have often noticed that I would have been able to solve practical problems in C elegantly if there had been a way of creating a ‘virtual FILE’ and attaching the necessary callbacks for events such as buffer full, input requested, close, flush. It should then be possible to use a large part of the stdio.h functions, e.g. fprintf unchanged. Is there a framework enabling one to do this? If not, is it feasible with a moderate amount of effort, on at least some platforms?
Possible applications would be:
To write to or read from a dynamic or static region of memory.
To write to multiple files in parallel.
To read from a thread or co-routine generating data.
To apply a filter to another (virtual or real) FILE.
Support for file formats with indirection (like #include).
A C pre-processor(?).
I am less interested in solutions for specific cases than in a framework to let you roll your own FILE. I am also not looking for a virtual filesystem, but rather virtual FILE*s that I can pass to the CRT.
To my disappointment I have never seen anything of the sort; as far as I can see C11 considers FILE entirely up to the language implementer, which is perhaps reasonable if one wishes to keep the language (+library) specifications small but sad if you compare it with Java I/O streams.
I feel sure that virtual FILEs must be possible with any (fully) open source implementation of the C run-time, but I imagine there might be a large number of details making it trickier than it seems, and if it has already been done it would be a shame to reduplicate the effort. It would also be greatly preferable not to have to modify the CRT code. Without open source one might be able to reverse engineer the functions supplied, but I fear the result would be far too vulnerable to changes in unsupported features, unless there were a commitment to a set of interfaces. I suppose too that any system for which one can write a device driver would allow one to create a virtual device, but I suspect that of being unnecessarily low-level and of requiring one to write privileged code.
I have to admit that while I have code that would have benefited from virtual FILEs, I have no current requirement for it; nonetheless it is something I have often wondered about and that I imagine could be of interest to others.
This is somewhat similar to a-reader-interface-that-consumes-files-and-char-in-c, but there the questioner did not hope to return a virtual FILE; the answer, however, using fmemopen, did.
There is no standard C interface for creating virtual FILE*s, but both the GNU and the BSD standard libraries include one. On linux (glibc), you can use fopencookie; on most *BSD systems, funopen (including Mac OS X). (See Note 1)
The two interfaces are similar but slightly different in some details. However, it is usually very simple to adapt code written for one interface to the other.
These are not complete virtualizations. They associated the FILE* with four callbacks and a void* context (the "cookie" in fopencookie). The callbacks are read, write, seek and close; there are no callbacks for flush or tell operations. Still, this is sufficient for many simple FILE* adaptors.
For a simple example, see the two answers to Write simultaneousely to two streams.
Notes:
funopen is derived from "functional open", not from "file unopen".

Modifying the bio structure in linux

I am attempting to modify the bio structure (in blk_types.h) for linux-3.2.0 (running Ubuntu). The only thing I need to do to this structure is to add an additional variable to keep track of an integer variable (it is for a tainting algorithm). However, adding a single line such as "int id;" to the structure halts the boot sequence of the OS.
It compiles, but when booting it gives the following error:
>Gave up wiating for root device. Common problems:
>Boot args
>check rootdelay= ...
>check root= ...
>missing modules (cat /proc/modules; ls /dev)
>ALERT! /dev/disk/by-uuid/15448888-84a0-4ccf-a02a-0feb3f150a84 does not exist. Dropping to a shell!
>BusyBox Built In Shell ...
>(initramfs)
I took a look around using the given shell and could not find the desired file system by uuid or otherwise (no /dev/sda). Any ideas what might be going on?
Thanks,
-Misiu
I suppose you are trying to modify the Linux kernel header bio.h, not its userland "friend" bui.h.
Said that I must warn you that in many places around kernel sizeof() may be used which is more portable and perhaps some other implementation or API may expect some fixed size. If the later is true then you'll have problems since bio' struct size has been changed by you.
It is a guessing with no further investigation from my side (I mean I hadn't investigate about bio in detail) but when patching the Linux kernel one must make sure of any possible side effects and take the whole scenario on account, specially when modifying lower levels implementation.
Bio helper functions do lots of low level operations on bio struct, take a loot at bio_integrity.c for example.
I managed to fix the problem with your help Caf. Though re-building/installing the modules did not seem to help immediately, I was able to get the system to boot by building the SATA drivers into the kernel, as advised by this forum thread: https://unix.stackexchange.com/questions/8405/kernel-cant-find-dev-sda-file-during-boot.
Thanks for your help,
-Misiu

Windows equivalent to Linux's readahead syscall?

Is there a Windows equivalent to Linux's readahead syscall?
EDIT:
I would like a full function signature if possible, showing the equivalent offset/count parameters (or lower/upper).
Eg:
The Linux function signature is:
ssize_t readahead(int fd, off64_t *offset, size_t count);
and an example of it's use is
readahead(file, 100, 500);
Where "file" is a file descriptor previously set by a function like mmap. This call is reading 500 bytes at index 100.
EDIT 2:
Please read this if you are unsure what readahead does: http://linux.die.net/man/2/readahead
Yes. It is FileSystemControl FSCTL_FILE_PREFETCH.
It is used in Windows Vista and above for prefetching both when an application starts and at boot time.
It is also used by the SuperFetch technology that uses heuristics to load applications at approximately the times of day you generally use them.
FSCTL_FILE_PREFETCH itself is not documented on MSDN, but it is easy to figure out the parameter format by examining the DeviceIoControl calls made on app startup: Just start an application in the debugger that already has a .pf file in the c:\Windows\Prefetch directory and break on DeviceIoControl (or if you're using a kernel debugger, break when the NTFS driver receives its first FSCTL_FILE_PREFETCH). Examine the buffer passed in and compare it with the .pf file and the range actually used later. I did this once out of curiosity but didn't record the details.
In case you are unfamiliar with DeviceIoControl and IRP_MJ_FILESYSTEM_CONTROL, here are some links to look at:
FileSystemControl at the IRP level IRP_MJ_FILESYSTEM_CONTROL
DeviceIoControl, which is used to invoke FileSystemControl IRPs
Structure of IO Control Codes
As of Windows 8, there exists a more or less direct equivalent to madvise(MADV_WILLNEED), which is effectively the same thing (Windows has an unified VM/cache system).
Assuming that you have memory-mapped the file, you can thus use PrefetchVirtualMemory to prefetch it.
This is still slightly more complicated than you'd wish, but not nearly as harsh as DeviceIoControl. Also note that you can easily prefetch several independent, discontinuous ranges.
I am not sure if I understand correctly, in what you said 'Where "file" is a file descriptor previously set by a function like mmap. This call is reading 500 bytes at index 100.' That sounds suspiciously like seeking to the offset and read 500 bytes... but you want it to be pre-fetched ahead...
In C Code, it would look something like this:
fseek(fp, 100, SEEK_CUR);
fread(&data, 500, 1, fp);
But prefetching it, I guess, you would want to hook up some kind of events using waithandles, and when the event gets raised, the data gets stored somewhere in a buffer...
To be honest, I have not come across a such thing that does pre-fetching data...but Ray's answer surprised me, but then again it is only for Vista upwards, if you want to maintain compatibility...that's something to keep in mind... but the links below may be of help...
Ok, there was a blog discussing this, a library written in Delphi, the source code is here, browsing the code here, ok, it may not be what you want but it may help you point in the direction... Sorry if its not what you are looking for...
Hope this helps,
Best regards,
Tom.

Converting Win16 C code to Win32

In general, what needs to be done to convert a 16 bit Windows program to Win32? I'm sure I'm not the only person to inherit a codebase and be stunned to find 16-bit code lurking in the corners.
The code in question is C.
The meanings of wParam and lParam have changed in many places. I strongly encourage you to be paranoid and convert as much as possible to use message crackers. They will save you no end of headaches. If there is only one piece of advice I could give you, this would be it.
As long as you're using message crackers, also enable STRICT. It'll help you catch the Win16 code base using int where it should be using HWND, HANDLE, or something else. Converting these will greatly help with #9 on this list.
hPrevInstance is useless. Make sure it's not used.
Make sure you're using Unicode-friendly calls. That doesn't mean you need to convert everything to TCHARs, but means you better replace OpenFile, _lopen, and _lcreat with CreateFile, to name the obvious
LibMain is now DllMain, and the entire library format and export conventions are different
Win16 had no VMM. GlobalAlloc, LocalAlloc, GlobalFree, and LocalFree should be replaced with more modern equivalents. When done, clean up calls to LocalLock, LocalUnlock and friends; they're now useless. Not that I can imagine your app doing this, but make sure you don't depend on WM_COMPACTING while you're there.
Win16 also had no memory protection. Make sure you're not using SendMessage or PostMessage to send pointers to out-of-process windows. You'll need to switch to a more modern IPC mechanism, such as pipes or memory-mapped files.
Win16 also lacked preemptive multitasking. If you wanted a quick answer from another window, it was totally cool to call SendMessage and wait for the message to be processed. That may be a bad idea now. Consider whether PostMessage isn't a better option.
Pointer and integer sizes change. Remember to check carefully anywhere you're reading or writing data to disk—especially if they're Win16 structures. You'll need to manually redo them to handle the shorter values. Again, the least painful way to deal with this will be to use message crackers where possible. Otherwise, you'll need to manually hunt down and convert int to DWORD and so on where applicable.
Finally, when you've nailed the obvious, consider enabling 64-bit compilation checks. A lot of the issues faced with going from 16 to 32 bits are the same as going from 32 to 64, and Visual C++ is actually pretty smart these days. Not only will you catch some lingering issues; you'll get yourself ready for your eventual Win64 migration, too.
EDIT: As #ChrisN points out, the official guide for porting Win16 apps to Win32 is available archived, and both fleshes out and adds to my points above.
Apart from getting your build environment right, Here are few specifics you will need to address:
structs containing ints will need to change to short or widen from 16 to 32 bits. If you change the size of the structure and this is loaded/saved to disk you will need write data file upgrade code.
Per window data is often stored with the window handle using GWL_USERDATA. If you widen some of the data to 32 bits, your offsets will change.
POINT & SIZE structures are 64 bits in Win32. In Win16 they were 32 bits and could be returned as a DWORD (caller would split return value into two 16 bit values). This no longer works in Win32 (i.e. Win32 does not return 64 bit results) and the functions were changed to accept a pointers to store the return values. You will need to edit all of these. APIs like GetTextExtent are affected by this. This same issue also applies to some Windows messages.
The use of INI files is discouraged in Win32 in favour of the registry. While the INI file functions still work you will need to be careful with Vista issues. 16 bit programs often stored their INI file in the Windows system directory.
This is just a few of the issues I can recall. It has been over a decade since I did any Win32 porting. Once you get into it it is quite quick. Each codebase will have its own "feel" when it comes to porting which you will get used to. You will probably even find a few bugs along the way.
There was a definitive guide in the article Porting 16-Bit Code to 32-Bit Windows on MSDN.
The original win32 sdk had a tool that scanned source code and flagged lines that needed to be changed, but I can't remember the name of the tool.
When I've had to do this in the past, I've used a brute force technique - i.e.:
1 - update makefiles or build environment to use 32 bit compiler and linker. Optionally, just create a new project in your IDE (I use Visual Studio), and add the files manually.
2 - build
3 - fix errors
4 - repeat 2&3 until done
The pain of the process depends on the application you are migrating. I've converted 10,000 line programs in an hour, and 75,000 line programs in less than a week. I've also had some small utilities that I just gave up on and rewrote (mostly) from scratch.
I agree with Alan that trial and error is probably the best way.
Here are some good tips.
Agreed that the compiler will probably catch most of the errors. Also, if you are using "near" and "far" pointers you can remove those designations -- a pointer is just a pointer in Win32.

Resources