Unix - use of the different drivers trees? - c

Context :
My question has a strong assumption : no user can list the tree of drivers.
I Was reading this (organization of the different drivers in Linux/Unix.
If a new operating system was created and no user could list the tree of drivers, should such a complicated tree needed ?
My feeling is : no, as far as the kernel is able to find one driver very fast.
Then it could be relevant to just limit ourselves to an array of struct like so:
struct descript_driver {
/* the usual struct with the functions
* pointers(.open = blah, .mmap = blah and so on).
*/
struct actions act;
char * driver_name;
char * vendor_name;
int vendorid;
int class_type; // GRAPHIC, NETWORK, CAMERA (#define or enum)...
int major_id;
int minor_id;
};
/* 256 is just an example. It could be more, or less.
* There are up to 256 majors but potentially a lot of minors.
* And each one has its index.
* Addressing is O(1).
*/
struct descript_driver array_of_drivers[256];
And having the drivers/kernel remembering its index only to flow in the array.
Interrupts would still take the major number.
And thanks to the minor number, it is still easy to find the right function to call in O(1).
Is there something wrong in my thought ? This is an important point to polish my project.
Thanks

Related

How to determine file type from kernel module?

Is there something like struct dirent* -> d_type that contains DT_REG, DT_DIR, DT_SOCK and etc. for kernel structures, for example for struct file? Looking at its fields, I cant find anything for this purpose.
Maybe someone knows how readdir determines d_type? I am looking at its implementation here https://github.com/lattera/glibc/blob/master/dirent/readdir.c and I cant understand what is going here.
Ubuntu18.04, 4.15.0-45 kernel version
The struct inode field i_mode is a bit-field that can be checked using the standard S_ISDIR, S_ISREG, S_ISLNK et al macros:
/*
* Keep mostly read-only and often accessed (especially for
* the RCU path lookup and 'stat' data) fields at the beginning
* of the 'struct inode'
*/
struct inode {
umode_t i_mode;
unsigned short i_opflags;
kuid_t i_uid;
kgid_t i_gid;
.
.
.
An example of its use in ext4 kernel code:
/*
* Test whether an inode is a fast symlink.
* A fast symlink has its symlink data stored in ext4_inode_info->i_data.
*/
int ext4_inode_is_fast_symlink(struct inode *inode)
{
if (!(EXT4_I(inode)->i_flags & EXT4_EA_INODE_FL)) {
int ea_blocks = EXT4_I(inode)->i_file_acl ?
EXT4_CLUSTER_SIZE(inode->i_sb) >> 9 : 0;
if (ext4_has_inline_data(inode))
return 0;
return (S_ISLNK(inode->i_mode) && inode->i_blocks - ea_blocks == 0);
}
return S_ISLNK(inode->i_mode) && inode->i_size &&
(inode->i_size < EXT4_N_BLOCKS * 4);
}
Note that you need to be really careful traversing such kernel structures. If you don't take the proper locks, they can change out from under the thread examining them.

generic stack implementation in linux core

I am writing a patch to bcache Linux module and struggle to find generic LIFO implementation in Linux core. I have found several FIFO implementations both on defines and without. However, nothing alike for LIFO.
Where can one find one? Preferably C not asm and not based on defines, but any should work.
If no abstract LIFO is provided, what are the easiest structures to implement LIFO on (generic stack realization in Linux core for instance)?
If the LIFO has fixed maximum depth, and is not dynamically allocated, then it is simply something like
#define LIFO_MAXDEPTH 16
static spinlock_t lifo_lock = SPIN_LOCK_UNLOCKED;
static size_t lifo_count = 0;
static struct item lifo_entry[LIFO_MAXDEPTH];
int lifo_push(const struct item *from)
{
spin_lock(&lifo_lock);
if (lifo_count >= LIFO_MAXDEPTH) {
spin_unlock(&lifo_lock);
return -1;
}
lifo_entry[lifo_count++] = *from;
spin_unlock(&lifo_lock);
return 0;
}
int lifo_pop(struct item *to)
{
spin_lock(&lifo_lock);
if (lifo_count < 1) {
spin_unlock(&lifo_lock);
return -1;
}
*to = lifo_entry[--lifo_count];
spin_unlock(&lifo_lock);
return 0;
}
Because we only need to keep it locked for very short durations, a spinlock should suffice.
If the LIFO is dynamically allocated, things get more complicated. In particular, because we might have to call kmalloc() or kfree(), we cannot use a spinlock. You'd also want to split the stack into page-sized chunks, since higher-order allocations may fail. Then you must consider things like nefarious users trying to use the facility for DOS attacks, and so on.

How to determine the size of a PIM within an AUTOSAR Runnable?

How can I determine the size of a PIM (Per Instance Memory) in c from inside a Runnable (without looking it up in the generated RTE and adding a fix value)?
Situation:
Runnable Foo has access to two PIMs Pim1 and Pim2. In the example the data from Pim1 shall be copied to Pim2.
Not only because of security and safety I need to check the size of both PIMs in order NOT to overwrite illegal data areas.
I know that the size of the PIM is configured in the SW-C description (SWCD). But as the SWCD may be changed after code implementation and in order to keep the code of the Runnable more generic, the size checking should not be based on fix values.
I also considered the problem of the sizeof for an array:
How to find the 'sizeof'(a pointer pointing to an array)?
For the PIMs the following code is generated by the RTE-Generator:
In Rte_Type.h
typedef uint8 Rte_DT_DtImplRec1_0;
typedef uint16 Rte_DT_DtImplRec1_1;
typedef struct
{
Rte_DT_DtImplRec1_0 var1;
Rte_DT_DtImplRec1_1 var2;
Rte_DT_DtImplRec1_2 var3;
} DtImplRec1;
typedef uint8 Rte_DT_DtImplAry1_0;
typedef Rte_DT_DtImplAry1_0 DtImplAry1[5];
In Rte.c
VAR(DtImplRec1, RTE_VAR_DEFAULT_RTE_PIM_GROUP) Rte_FOO_Pim1;
VAR(DtImplAry1, RTE_VAR_DEFAULT_RTE_PIM_GROUP) Rte_FOO_Pim2;
In Rte_FOO.h
#define Rte_Pim_Pim1() (&Rte_FOO_Pim1)
#ifdef RTE_PTR2ARRAYBASETYPE_PASSING
# define Rte_Pim_Pim2() (&((*RtePim_Pim2())[0]))
#else
# define Rte_Pim_Pim2() RtePim_Pim2()
#endif
#define RtePim_Pim2() (&Rte_FOO_Pim2)
Note that the define for array PIMs might also be changing, depending on the RTE_PTR2ARRAYBASETYPE_PASSING “switch”.
The following “access” is generated for the FOO template:
DtImplRec1 *Rte_Pim_Pim1(void);
Rte_DT_DtImplAry1_0 *Rte_Pim_Pim2(void)
The code for the Foo-Runnable may look like this:
FUNC(void, FOO_CODE) Foo(void)
{
DtImplRec1 *pim1 = Rte_Pim_Pim1();
Rte_DT_DtImplAry1_0 *pim2 = Rte_Pim_Pim2();
uint8 sizeOfPim1a = sizeof(Rte_Pim_Pim1()); /* always returns 4 as the size of the pointer */
uint8 sizeOfPim1b = sizeof(*Rte_Pim_Pim1()); /* evaluates to 6 */
uint8 sizeOfPim1c = sizeof(DtImplRec1); /* evaluates to 6 */
uint8 sizeOfPim1d = sizeof(Rte_FOO_Pim1); /* evaluates to 6 */
uint8 sizeOfPim2a = sizeof(Rte_Pim_Pim2()); /* always returns 4 as the size of the pointer */
uint8 sizeOfPim2b = sizeof(*Rte_Pim_Pim2()); /* evaluates to 1 */
uint8 sizeOfPim2c = sizeof(Rte_DT_DtImplAry1_0); /* evaluates to 1: sizeof(uint8) */
uint8 finalSize = MIN(sizeOfPim1b, sizeOfPim2b);
memcpy( pim2, pim1, finalSize ); /* (use of) memcpy is not the topic here */
}
To make my problem more "visible", here is a Callback-Runnable example for writing a DID via diagnostics:
FUNC(Std_ReturnType, FOO_CODE)
DataServices_Data_FFFF_WriteData(P2CONST(uint8, AUTOMATIC, RTE_APPL_DATA) Data, Dcm_OpStatusType OpStatus, P2VAR(Dcm_NegativeResponseCodeType, AUTOMATIC, RTE_APPL_DATA) ErrorCode)
{
Std_ReturnType ret = E_NOT_OK;
#define sizeOfPim1 (5) /* how to determine the PIM size here if we do not know anything about it here? (PIM structure can change without modifying the code here) */
#define sizeOfDidFFFF (5) /* This is even another problem: How to determine the size of a DID. I will create another discussion thread for this question. */
/* Instead of this if-condition, an assert during compile-time would also be appropriate */
if( sizeOfPim1 == sizeOfDidFFFF )
{
/* We have to make sure that we do not copy more bytes as of the size of Pim1 */
memcpy( Rte_Pim_Pim1(), Data, sizeOfPim1 ); /* (use of) memcpy is not the topic here */
ret = E_OK;
}
return ret;
}
I don't have here any AUTOSAR environment to test this, so, please, if you try any of this, just let me know if it works. Besides, I am not an expert and it is quite a long time I don't write AUTOSAR code, so I will probably be missing something. I also don't want to publicize any RTE generator from any vendor, so I will cite only the standard.
Use sizeof(DtImplAry1)
You define that type and give it as input to the RTE generator, so you know the name. If your SWC doesn't make explicit use of that type the RTE generator could not include it in your .h, but you could add it manually to you SWC arxml. I think all tools out there allow to do this without having to edit the arxml by hand, just look for the option to include additional SWC types in your tool.
Use Instance API to access SWC data
The standard specifies a variable of type Rte_CDS_FOO to hold all pointers to PIMs of the SWC (among other things) if you enable the API (look for it in your tool).
Besides, a variable Rte_Inst_FOO should be available to you, declared as extern in your header. You could do sizeof(*Rte_Inst_FOO->Pim_Pim2).
EDIT: reply to some of your comments
I guess the reason you don't find the CDS is because of this (from Specification of RTE, 4.2.2, 5.4 RTE Data Structures):
The [CDS and Instance handler] definitions only apply to RTE generators operating in compatibility mode – in this mode the instance handle and the component data structure have to be defined even for those (object-code) software components for which multiple instantiation is forbidden to ensure compatibility.
Also,
[SWS_Rte_03793] If a software component does not support multiple instantiation,the name of the component data instance shall be Rte_Inst_cts, where cts is the component type symbol of the AtomicSwComponentType. (SRS_Rte_00011)
So, when the RTE-generator adheres to this compatibility mode, those variables must be there. If you are using a vendor specific solution, well, try to tag the question with that vendor name also, hopefully somebody can answer.
Assert at compile time
I am not going to ask why you are doing this, but IMHO I think it does not sound right, does it makes sense for the receiving buffer to be smaller that the data to copy?. Maybe it is better to assert at compile time if the buffer is smaller than your struct. Or you could define your array instead to be a struct and cast it if needed (if your are following MISRA rules, maybe you will have problems with it, just check). Just for reference, compile time assertions can use sizeof.
You have several problems here:
a) your sizeof(*pim1) returns 6 because of padding, because you start with an uint8, the second is uint16, and I guess the 3rd ist also uint16.
That's, why you should rather sort them by type size/alignment .. biggest to smallest
uint32
uint16
uint8
Even though, the elements might not be ordered anymore, but it also decreases finally the gaps in memory created by the linker.
b) the pim2 is an array, you can not get the array len/size from the pointer.
But, you should have the Rte definition of DtImplAry1.
typedef uint8 Rte_DT_DtImplAry1_0;
typedef Rte_DT_DtImplAry1_0 DtImplAry1[5]; // <-- taken in through Rte_Foo_Type.h (includes Rte_Type.h
uint32 ary_len = sizeof(DtImplAry1) / sizeof(DtImplAry1[0]);

How can I implement a portable pointer compare and swap?

I have found this code for compareAndSwap in a StackOverflow answer:
boolean CompareAndSwapPointer(volatile * void * ptr,
void * new_value,
void * old_value) {
#if defined(_MSC_VER)
if (InterlockedCompareExchange(ptr, new_value, old_value) == old_value) return false;
else return true;
#elif (__GNUC__ * 10000 + __GNUC_MINOR__ * 100 + __GNUC_PATCHLEVEL__) > 40100
return __sync_bool_compare_and_swap(ptr, old_value, new_value);
#else
# error No implementation
#endif
}
Is this the most proper way of having portable fast code, (Except assembly inlining).
Also, one problem is that those specific builtin methods have different parameters and return values from one compiler to another, which may require some additional changes like the if then else in this example.
Also another problem would be the behavior of these builtin methods in the machine code level, do they behave exactly the same ? (e.g use the same assembly instructions)
Note: Another problem would be if there is many supported platforms not just (Windows and Linux) as in this example. The code might get very big.
I would use a Hardware Abstraction Layer, (HAL) that allows generic code to be common - and any portable source can be included and build for each platform.
In my opinion, this allows for better structured and more readable source.
To allow you to better understand this process I would suggest Google for finding examples and explanations.
Hopefully this brief answer helps.
[EDIT] I will attempt a simple example for Bionix, to show how to implement a HAL system...
Mr A wants his application to run on his 'Tianhe-2' and also his 'Amiga 500'. He has the cross compilers etc and will build both binaries on his PC. He want to read keys and print to the screen.
mrAMainApplication.c contains the following...
#include "hal.h"
// This gets called every time around the main loop ...
void mainProcessLoop( void )
{
unsigned char key = 0;
// scan key ...
key = hal_ReadKey();
if ( key != 0 )
{
hal_PrintChar( key );
}
}
He then creates a header file (Remember - this is an example, not working code! )...
He creates hal.h ...
#ifndef _HAL_H_
#define _HAL_H_
unsigned char hal_ReadKey( void );
unsigned char hal_PrintChar( unsigned char pKey );
#endif // _HAL_H_
Now Mr A needs two separate source files, one for his 'Tianhe-2' system and another for his Amiga 500...
hal_A500.c
void hal_ReadKey( void )
{
// Amiga related code for reading KEYBOARD
}
void hal_PrintChar( unsigned char pKey )
{
// Amiga related code for printing to a shell...
}
hal_Tianhe2_VERYFAST.c
void hal_ReadKey( void )
{
// Tianhe-2 related code for reading KEYBOARD
}
void hal_PrintChar( unsigned char pKey )
{
// Tianhe-2 related code for printing to a shell...
}
Mr A then - when building for the Amiga - builds mrAmainApplication.c and hal_A500.c
When building for the Tianhe-2 - he uses hal_Tianhe2_VERYFAST.c instead of hal_A500.c
Right - I've written this example with some humour, this is not ear-marked at anyone, just I feel it makes the example more interesting and hopefully aids in understanding.
Neil
In modern C, starting with C11, use _Atomic for the type qualification and atomic_compare_exchange_weak for the function.
The newer versions of gcc and clang are compliant to C11 and implement these operations in a portable way.
Take a look at ConcurrencyKit and possibly you can use higher level primitives which is probably what most of the time people really want. In contrast to HAL which somewhat OS specific, I believe CK works on Windows and with a number of non-gcc compilers.
But if you are just interested in how to implement "compare-and-swap" or atomic actions portably on a wide variety of C compilers, look and see how that code works. It is all open-source.
I suspect that the details can get messy and they are not something that in general will make for easy or interesting exposition here for the general public.

alternative to container_of()

I am a newbie trying to code a serial driver(PCI based ) and I don't want to use the container_of() for lack of downward compatibility.The kernel version I may compile the module
would be < 2.6.x so I want to make it compatible with most of the old and new versions.
i want to access the structure member(s) of a serial card driver.the structure is a custom one containing the atomic variable for example - use_count and the related operation on it-- atomic_inc(&serial_card->use_count).I dont want to access them by using the container_of() function which will give me the containing structure
Is there any alternate to container_of() function.If I am not wrong the text LINux device drivers by Allesandro Roubini describes a way on page no 174 | Chapter 6: Advanced Char Driver Operations.
But I am still fixed about how to assign something like struct scull_dev *dev = &scull_s_device.
if the structure itself contains a variable of type struct pc_device *dev,the above statement populates a similar variable and that is assigned to dev,
in my case i have declared a structure and related function as below
struct serial_card
{
unsigned int id; // to identify the each card
//atomic_t use_count; // variable used to check whether the device is already opened or not
wait_queue_head_t rx_queue[64]; // queue in which the process are stored
unsigned int data_ready[64]; // queue in which the process is ready
unsigned int rx_chan; // used by interrupt handler
unsigned int base, len; // holds physical base address , holds the total area ( for each card )
unsigned int *base; // holds virtual address
/*struct cdev cdev; // kernel uses this structure to represent the EACH char device
not using the new method to represent char devices in kernel instead using the old method of register_chrdev();*/
struct pci_dev *device; // pci_dev structure for EACH device.
//struct semaphore sem; //Semaphore needed to handle the co-ordination of processes,use incase need arises
};
static struct serial_card *serial_cards; // pointer to array of structures [ depending on number of cards ],NO_OF_CARDS #defined in header file
static int serialcard_open(struct inode *inode,struct file *filep)
{
//getting the structure details of type struct serialcard,using the pointer inode->i_cdev and field type cdev
//struct serial_card *serial_cards = container_of(inode->i_cdev, struct serial_card, cdev);
// read the current value of use_count
static int Device_Open = 0;
if ( Device_Open ) //Device_Open is static varibale used here for checking the no of times a device is opened
{
printk("cPCIserial: Open attempt rejected\n");
return -EBUSY;
}
Device_Open++;
// using the card so increment use_count
//atomic_inc(&serial_cards->use_count);
//filep->private_data = serial_cards;
return 0;
}
the complete description on page 174 - 175 is as follows
Single-Open Devices
The brute-force way to provide access control is to permit a device to be opened by
only one process at a time (single openness). This technique is best avoided because it
inhibits user ingenuity. A user might want to run different processes on the same
device, one reading status information while the other is writing data. In some cases,
users can get a lot done by running a few simple programs through a shell script, as
long as they can access the device concurrently. In other words, implementing a singleopen
behavior amounts to creating policy, which may get in the way of what your
users want to do. Allowing only a single process to open a device has undesirable properties, but it is also the easiest access control to implement for a device driver, so it’s shown here.
The source code is extracted from a device called scullsingle.
The scullsingle device maintains an atomic_t variable called scull_s_available; that
variable is initialized to a value of one, indicating that the device is indeed available.
The open call decrements and tests scull_s_available and refuses access if somebody
else already has the device open:
static atomic_t scull_s_available = ATOMIC_INIT(1);
static int scull_s_open(struct inode *inode, struct file *filp)
{
struct scull_dev *dev = &scull_s_device; /* device information */
if (! atomic_dec_and_test (&scull_s_available)) {
atomic_inc(&scull_s_available);
return -EBUSY; /* already open */
}
/* then, everything else is copied from the bare scull device */
if ( (filp->f_flags & O_ACCMODE) = = O_WRONLY) {
scull_trim(dev);
filp->private_data = dev;
return 0; /* success */
}
The release call, on the other hand, marks the device as no longer busy:
static int scull_s_release(struct inode *inode, struct file *filp)
{
atomic_inc(&scull_s_available); /* release the device */
return 0;
}
Normally, we recommend that you put the open flag scull_s_available within the
device structure (Scull_Dev here) because, conceptually, it belongs to the device. The
scull driver, however, uses standalone variables to hold the flag so it can use the same
device structure and methods as the bare scull device and minimize code duplication.
Please let me know any alternative for this
thanks and regards
perhaps I am missing the point, but "cotainer_of" is not a function, but a macro. If you have porting concerns, you can safely define it by yourserlf if the system headers don't implement it. Here a basic implementation:
#ifndef container_of
#define container_of(ptr, type, member) \
((type *) \
( ((char *)(ptr)) \
- ((char *)(&((type*)0)->member)) ))
#endif
Or here's the implementation - more accurate - from recent linux headers:
#define container_of(ptr, type, member) ({ \
const typeof( ((type *)0)->member ) *__mptr = (ptr);
(type *)( (char *)__mptr - offsetof(type,member) );})
In that code the containerof is used to store and retrieve the correct dev structure easily. The correct structure can be retrieved inside the read and write functions also without accessing to the private_data.
I do not know why you do not want to use private->data and containerof, but you can always retrieve your minor number from the struct file pointer.
int minor=MINOR(filp->f_dentry_d_inode->i__rdev);
then accessing to your multiple devices vector using something like
struct scull_dev* dev = &scull_devices[minor]:
and using it.
You will need to use filp->privatedata to store "per-open" information that you also use in read/write. You will need to decide what to store to ensure that the right information is available.
Probably you want two structures. One "device structure" and one "open structure". The open structure can get dynamically allocated in "open" and stored at private_data. In release, it gets freed. It should have the members such that you can use them in read/write to get access to the data you need.
The device structure is going to be per "card". In your driver init, you probably want to loop on the number of cards and create a new device structure (serial_card) for each. You can make them a static array, or dynamically allocate, it doesn't matter. I would store the minor number in the structure as well. The minor number is chosen by you, so start with 1 and go through #cards. You can reserve "0" for a system level interface, if you want, or just start at 0 for the cards.
In open, you will get the minor number that the user opened. Go through your serial_card list looking for a match. If you don't find it, error out of open. Otherwise, you have your info and can use it to allocate a "open structure", populate it, and store it in filp->private_data.
#Giuseppe Guerrini Some compiler just cannot recognize the linux implementation of container_of.
The basic define is fine, but I wonder if there is any safety or compatibility risk at this implementation:
#ifndef container_of
#define container_of(ptr, type, member) \
((type *) \
( ((char *)(ptr)) \
- ((char *)(&((type*)0)->member)) ))
#endif

Resources