1

I have to modify a driver that runs on linux to add a callback function that is invoked from an external application. I already have the code implemented but when it is executed when the computer starts up, the system gives an error and is blocked.

This is my new code on the driver side:

typedef void (*callbackFunctionNoParams) ();

typedef struct T_EXI_CONFIGURE_BUS_
{
    T_mode mode;
    unsigned short NumeroRT;
    T_SA_Enable SA_Enable;
    unsigned short MINOR_CYCLE;
    callbackFunctionNoParams callback;

} T_EXI_CONFIGURE_BUS;

typedef struct PciExiDev_
{
   /**
    * It represents a char device to read/write
    */
   struct cdev charDevice;
   /**
    * IRQ assigned
    */
   unsigned int irq;

   /**
    * Callback function to be invoked
    */

   callbackFunctionNoParams callback;

   /**
    * Device control block
    */
   EXI_DCB theDCB;
} PciExiDev;

Execution code on driver side:

static long exi_ioctl( struct file * filep, unsigned int cmd, unsigned long arg )
{
   PciExiDev * aPciExiDev = (PciExiDev *) filep->private_data;

   int result = SUCCESS;
   int i, j;
   long ret = 0;
   //printk("Ioctl received %d.\n",cmd);
   switch( cmd )
   {
      case FIO_EXI_CONFIGURE_BUS:
      {
         T_EXI_CONFIGURE_BUS config;
        T_LISTA_TRANS *auxTrans1, *auxTrans2;
        T_TRANSACTION_DCB *transDCB1;
         T_OPI opi;
         T_EXIS exis;
         unsigned short dato;
         unsigned short datolong[2];
         unsigned short ControlBlock[12];
//       printk("Exi configure bus initiated.\n");
         printk("TNB. Exi ioctl CONFIGURE BUS.\n");

         copy_from_user( &config, (T_EXI_CONFIGURE_BUS *) arg, sizeof(T_EXI_CONFIGURE_BUS) );

         LeerDatos( &aPciExiDev->theDCB, OPI_ADDRESS, 1, (unsigned short *) &opi, 1 );

         aPciExiDev->callback = config.callback;
         aPciExiDev->theDCB.modo = config.mode;
         aPciExiDev->theDCB.CicloMenor = config.MINOR_CYCLE;
         
         (*aPciExiDev->callback)();

...

New code on client side:

   if( theHWConfiguration.existExi() )
   {
      T_EXI_CONFIGURE_BUS bus_config;

      // Configura la tarjega exi en modo Bus Controller.
      bus_config.mode = BC;
      bus_config.NumeroRT = 28;
      bus_config.MINOR_CYCLE = 20;
      bus_config.callback = &bcInterruptHandler2;
      status = ioctl( A_fd_exi, FIO_EXI_CONFIGURE_BUS, reinterpret_cast<long>( &bus_config ) );
   }
   return status;
}

void C_EXI::bcInterruptHandler2()
{
   std::cout<< "bcInterruptHandler2" << endl;
}

And this is the execution code result:

Crash Image

If someone could help me or propose an alternative way of doing this I would be very grateful.

  • Are you trying to invoke a user-space function from kernel-space? – Gaurav Pathak Jan 14 '22 at 12:37
  • can you also please provide a translation of one of your comments? – BZKN Jan 14 '22 at 14:02
  • Related: https://stackoverflow.com/questions/2689975/is-it-possible-to-call-a-user-space-callback-function-from-kernel-space-in-linux – dbush Jan 14 '22 at 14:16
  • 1
    Yes @GauravPathak, to better describe the scenario; we have an application that communicates with a driver, at the moment only in that direction, but due to new requirements, now, when certain events occur on the driver side, it must inform the application; and I had thought that a callback function would be the solution but it is crashing the OS. Can you think of an alternative way to communicate from the driver to the application? – Antonio León Jan 17 '22 at 15:46
  • https://stackoverflow.com/questions/58639288/how-to-send-signal-from-linux-kernel-space-to-user-space-in-order-to-notify-abou – Gaurav Pathak Jan 18 '22 at 05:17
  • Well, I have found a solution to my problem, but as stated in some answers and comments, you can't use callback functions as we know them. Instead, I have opted for sending signals from the driver to the client app and the result has been perfect for my purpose. For those who are interested in this solution, I have based it on the code found on this web page: https://programmer.ink/think/linux-driver-practice-how-does-the-driver-send-signal-to-the -application.html; to whose author(s) I am very grateful for their publication. Regards. – Antonio León Jan 21 '22 at 11:32

2 Answers2

0

The crash image suggests that somewhere in your code you have an invalid pointer that you are trying to access. I am afraid I cannot debug your code with the little context provided, but I can give you some suggestions:

  • Try to avoid casting until is strictly necessary.
  • When you are casting to a pointer, double-check that this is exactly what you need to do.
  • In the error message there is also the call stack: take a look at it in order to identify where is the error.
  • You can simply add some printk("%p", pointer) in your code to debug the content of your variables.
  • Thanks for your answer Miguel; I have already seen that the test is wrong, I will review the code and try again. Greetings. – Antonio León Jan 17 '22 at 07:33
0

Your callback is bound to run at kernel space and then you write it to std::cout. While going through your code, it tells that there is a conflict between kernel mode address space and userside process address space. This means that if the callback function is declared in the userside but instead called in the kernel space, there would be an error.

BZKN
  • 1,499
  • 2
  • 10
  • 25
  • 1
    Ok, BKN, I see the problem you say; in any case, the final code will not have std::cout, it was just a test, but I see that the test is wrong. Thanks for your answer, I'll change the code and try again – Antonio León Jan 17 '22 at 07:30