Monday, April 8, 2024

Why sleep is not allowed in IRQ handler ?

You cannot sleep in an interrupt handler because interrupts do not have a backing process context, and thus there is nothing to reschedule back into. In other words, interrupt handlers are not associated with a task, so there is nothing to "put to sleep" and (more importantly) "nothing to wake up". They must run atomically.


This is not unlike other operating systems. In most operating systems,
interrupts are not threaded. Bottom halves often are, however.

The reason the page fault handler can sleep is that it is invoked only
by code that is running in process context. Because the kernel's own
memory is not pagable, only user-space memory accesses can result in a
page fault. Thus, only a few certain places (such as calls to
copy_{to,from}_user()) can cause a page fault within the kernel. Those
places must all be made by code that can sleep (i.e., process context,
no locks, et cetera).
- Robert Love.

In a system, there is a thread context and an interrupt context. Interrupts are invoked by the hardware, while threads are scheduler by the RTOS scheduler. Now when an interrupt occurs, any thread will be immediately pre-empted; the interrupt must run to completion and can only be preempted by a higher priority interrupt (where nested interrupts are supported). All pending interrupts will run to completion before the scheduler can run.

Mutex Story

Blocking on a mutex (or indeed any blocking kernel object) is a scheduling event. If you were to make any blocking call in an interrupt, the scheduler will never run. In practice an RTOS would either ignore the blocking call, raise an exception, or enter a terminal error handler.

Now lets imagine this from an interrupt handler's point of view.

  • If an interrupt handler attempts to get a mutex that is not available, what should it do? The interrupt handler cannot block like the thread (the kernel is not equipped to push the context of an interrupt handler or switch to a thread from an interrupt handler).

  • If the interrupt handler obtains the mutex, what higher priority code is there that could interrupt the interrupt handler and attempt to use the mutex? Is the interrupt handler going to release the mutex before completing?

  • How does the kernel assign ownership of the mutex to an interrupt handler? An interrupt handler is not a thread. If the interrupt handler does not release the mutex then how will the kernel validate that the mutex is being released by the owner?


Some Functions Which Sleep

The most common ones are listed below, but you usually have to read the code to find out if other calls are safe. If everyone else who calls it can sleep, you probably need to be able to sleep, too. In particular, registration and deregistration functions usually expect to be called from user context, and can sleep.

Issue Signature :

May 25 21:49:22 <hostname> kernel: amdgpu 0000:08:00.0: RAS: optional ras ta ucode is not available May 25 21:49:22 <hostname> kernel: BUG: sleeping function called from invalid context at mm/slab.h:567 May 25 21:49:22 <hostname> kernel: Call Trace: May 25 21:49:22 <hostname> kernel: dump_stack+0x8b/0xc8 May 25 21:49:22 <hostname> kernel: ___might_sleep.cold+0xb6/0xc6 May 25 21:49:22 <hostname> kernel: kmem_cache_alloc_trace+0x1ea/0x230


Some Functions Which Don’t Sleep

Some functions are safe to call from any context, or holding almost any lock.

Sleep in kmalloc(GFP_KERNEL) should not be allowed in IRQ or atomic context

Using GFP_KERNEL means that kmalloc can put the current process to sleep waiting for a page when called in low-memory situations. A function that allocates memory using GFP_KERNEL must, therefore, be reentrant and cannot be running in atomic context.

Using GFP_ATOMIC prevents sleeping by telling the memory allocation code that it's not allowed to sleep to satisfy the allocation - that's all. If the memory allocation code needs to sleep, and GFP_ATOMIC has been passed, then it will return an error to the caller instead.

Wednesday, April 20, 2022

Security Concepts

 Security Concepts


1. data flow diagram, tracking data flow and protecting the path using encryption - Confidentiality

2. root of trust/ chain of trust - Integrity

3. Multi-layer security - defense in depth to keep in mind before designing an APP. Supplementary protection.

4. Data Injection checks for Injection attack. Input/Output Validation/ Authentication

5. Protect the ROM Image using Chain of trust

6. Create security zone - memory / process data  --  Public, private or regulated data

7. Fail safe / Server Error response from Applications.

8. Proper Non-verbose error and error response.

9. Data residency spread across different zones.

10. TOC TOU , this is time of copy and time of use.

C programming - Remove Nth Node From End of Singly Link List

Remove Nth Node From End of List

/**
 * Definition for singly-linked list.
*/
struct ListNode {
   int val;
   struct ListNode *next;
};

struct ListNode* removeNthFromEnd(struct ListNode* head, int n)
{
    struct ListNode *f0 = head;
    struct ListNode *f1 = head;
    struct ListNode *f2 = head;
    struct ListNode *temp = head;
    int flag = 1;

    if((head ==  NULL) || (n < 0))
        return NULL;

    if(n == 0)
    {
        return head;
    }    
    else if(n == 1)
    {
        // if there is only one node in list
        if(head->next == NULL)
        {   
            free(head);
            return NULL;
        }    
        else
        {    
           while(f1->next != NULL)
           {
                f0 = f1;    
                f1 = f1->next;
           }    
        }
        free(f1);
        f0->next = NULL;
        return head;
    }
    
    n--;

    while(f2->next != NULL)
    {          
        if(n != 0)
        {        
           f2 = f2->next; 
           n--;
        }
        else
        {   
            f0 = f1; 
            f1 = f1->next;
            f2 = f2->next; 
            flag = 0;
        }
    } 
    if(flag != 0)
    {    
        temp = head->next;
        free(head);
    }
    else
    {
        f0->next = f1->next;
        temp = head;
        free(f1);
    }    
    return temp;
}

Sunday, April 17, 2022

C programming - count number of bits that are set in an integer ( without using loops )


#define bit(val, p)  ((val & (1 << p)) >> p)

int main()

{

    unsigned int val   = 0x12344;

    int count = 0;

    count = bit(val,0) +  bit(val,1) + bit(val,2) + bit(val,3)

            + bit(val,4) + bit(val,5) + bit(val,6) + bit(val,7)

            + bit(val,8) + bit(val,9) + bit(val,10) + bit(val,11)

            + bit(val,12) + bit(val,13) + bit(val,14) + bit(val,15)

            + bit(val,16) + bit(val,17) + bit(val,18) + bit(val,19)

            + bit(val,20) + bit(val,21) + bit(val,22) + bit(val,23)

            + bit(val,24) + bit(val,25) + bit(val,26) + bit(val,27)

            + bit(val,28) + bit(val,29) + bit(val,30) + bit(val,31);

    printf("\ncount  = %d\n", count);

    return 0;

}


Sunday, November 1, 2020

C programming - Count number of bits to be flipped to convert A to B

From :- https://aticleworld.com/interview-questions-on-bitwise-operators-in-c/

In this question, you need to count flipped bits that require to convert A to B. To accomplish this task you need to find the number of bits that are different in A and B.

Suppose, A = 8, B = 7
Binary representation of A => 00001000
Binary representation of B => 00000111
Here we have to flip highlighted four bits of A
to make it B.

 Algorithm

  1. Calculate XOR of A and B.With the help of XOR, we will discard the common bits and set the bits that are different in numbers A and B.
  2. Count the set bits of the above calculated XOR result.

Example code,

#include <stdio.h>
//function to calculate flipped bits
int CountFlippedBits(int A, int B)
{
int XorResult = 0;
int count = 0;
//Doing Ex-or
XorResult = (A ^ B);
//Count set bits
while (XorResult)
{
count += XorResult & 1;
XorResult >>= 1;
}
return count;
}
int main()
{
int A = 8;
int B = 7;
int ret = 0;
//Function return count of flipped bits
ret = CountFlippedBits(A,B);
printf("Flipped Bits = %d\n",ret);
return 0;
}