Showing posts with label interrupt. Show all posts
Showing posts with label interrupt. Show all posts

Saturday, August 18, 2012

UNDERSTANDING LINUX INTERRUPT HANDLER

Key points when thinking about Linux Interrupt handling mechanisms:

  • Linux kernel is not a process, but  a process manager
  • Kernel pages are not swappable, so no page fault can actually happen
  • When an interrupt occurs, the time taken by the interrupt handler is accounted in for the process's time slice which was currently in execution

The OS can switch to kernel mode in the following scenarios:

  1. Exception handling (Page fault/Illegal memory access etc)
  2. HW Interrupt. This can happen asynchronously as long as interrupts are enabled (Any form of interrupts including timer interrupts even for scheduler, can be taken into account)
  3. System calls
Kernel control paths:
  • System calls - executed in process context
  • Exception Handling - Again, caused during process instruction execution, hence again process context
  • H/W Interrupt - Can happen asynchronously and can have nothing to do with currently running process, hence runs in its own context - Interrupt context. 

Synchronization:

Kernel Pre-emption:

What is kernel pre-emption?
Kernel pre-emption is a mechanism in which a scheduler is allowed to forcibly evict the currently running process and replace it with another process of same or higher priority, even if the current process can still continue to run if allowed to.

In case of  kernel pre-emption, if interrupts are enabled, a high priority process can take over the execution over currently executing process. In this way, the first process control path is left unfinished.

In this situation, no other process code, other than that of an interrupt or exception handling can get executed in a uniprocessor system. In case of a multiprocessor system, this is not the case though!

Disabling Interrupts:

Another approach to achieve synchronization while executing in critical region is to disable interrupts. Note that, by disabling interrupts, we are in effect disabling both interrupts as well as scheduling. Only way to execute some other kernel control path can now be only in case of exception handling, which can never be ignored in any case (i.e. for cases like divide by zero kind of operations etc. it becomes a must do operation). Again, even though disabling interrupts can work well for a uniprocessor machine, the same does not hold good while working with a multiprocessor machines, as disabling interrupts on one processor does not stop the critical section of the code from being executed from another cpu.


Semaphores:

Since neither of the above two can effectively protect the critical resources from being accessed improperly, we need a mechanism for a process to lock the execution of the critical section from being simultaneously accessed by other processes (both in a uniprocessor & multiprocessor machines). There are different forms of locks available in the Linux kernel that can serve the locking purpose "ideally" under different situations, one among that being the Semaphore.

Semaphore is just a counter associated with a data structure.

Following attributes can be associated to describe a semaphore:
1. Has a counter
2. Has a list of all the tasks sleeping while waiting on this semaphore
3. Two APIs to handle this "semaphore" lock - up( ) & down( )

Normally a semaphore will have a default count value of 1 initialized when created.
The down( ) API is called whenever a thread that wants to gain access to the data structure to lock the access rights to itself. The down() will decrement the value of the semaphore count by 1 atomically and then check if the count value becomes negative. If not, it gets access to the data structure and continue executing. Mean while if another process comes down to access the same semaphore and calls down(), down API finds that the count value now turns negative, it is placed in the semaphore's wait list and moved to sleep state, while making a call to the scheduler to schedule a new process. 

Now, later when the first process finishes its access to the data structure, it will now decide to release the semaphore by calling the up(). This API would increment the count and checks if there are any pending processes in the waiting list and then wake up one of the process in the list and reschedules it for execution.

Spin Locks: 

Spin locks are normally used in interrupt handlers and other similar situations where it is not allowed to sleep. In case of a spin lock, if a process tries to gain the spin lock and fails, rather than sleeping, it would enter into a tight loop continuously checking for the spinlock availability. Thus, we can note that this kind of lock can hang an uniprocessor system and hence helpful only for a multi processor system. 

A spin lock is preferred over a semaphore under situations where we are not allowed to sleep as well as situations where it is much efficient to just loop continuously waiting for the lock than to bear the overhead of moving process to a list and rescheduling and bringing back in a later situation, as done by the semaphore.


Thursday, August 26, 2010

Jiffies: INTC and GPT timer crash

Ok, So after configuring INTC and GPT1, its now possible to proceed a bit further, where in I wait looping inside calibration_loop function waiting for jiffies to be updated.

Sure enough, I do receive the GPT1 interrupt when the timer overflows, however, I see a big crash happening as the interrupt is not getting correctly mapped.

Also, it must be noted that GPT1 is still not configured correctly for 1 ms delay, but rather need to wait for more than 10 min to get this crash.

Below is a log that I get when system crashes:


OMAP3 beagleboard.org # bootm 0x80300000
## Booting kernel from Legacy Image at 80300000 ...
   Image Name:   Puppy Linux
   Image Type:   ARM Linux Kernel Image (uncompressed)
   Data Size:    1399776 Bytes =  1.3 MB
   Load Address: 80008000
   Entry Point:  80008000
   Verifying Checksum ... OK
   Loading Kernel Image ... OK
OK


Starting kernel ...


Uncompressing Linux... done, booting the kernel.
<5>Linux version 2.6.35-rc3 (amar@amar-laptop) (gcc version 4.4.1 (Sourcery G++                                                                                                              Lite 2010q1-188) ) #12 PREEMPT Thu Aug 26 23:04:06 CEST 2010
CPU: ARMv7 Processor [411fc083] revision 3 (ARMv7), cr=10c53c7f
CPU: VIPT nonaliasing data cache, VIPT nonaliasing instruction cache
Machine: PuppyBeagle
Memory policy: ECC disabled, Data cache writeback
<7>On node 0 totalpages: 65536
<7>free_area_init_node: node 0, pgdat c02d4714, node_mem_map c02eb000
<7>  Normal zone: 512 pages used for memmap
<7>  Normal zone: 0 pages reserved
<7>  Normal zone: 65024 pages, LIFO batch:15
Built 1 zonelists in Zone order, mobility grouping on.  Total pages: 65024
<5>Kernel command line: console=ttyS2,115200n8 console=tty0 root=/dev/mmcblk0p2                                                                                                              rw rootfstype=ext3 rootwait omapfb.video_mode=1024x768MR-16@60
<6>PID hash table entries: 1024 (order: 0, 4096 bytes)
<6>Dentry cache hash table entries: 32768 (order: 5, 131072 bytes)
<6>Inode-cache hash table entries: 16384 (order: 4, 65536 bytes)
<6>Memory: 128MB 128MB = 256MB total
<5>Memory: 256916k/256916k available, 5228k reserved, 0K highmem
<5>Virtual kernel memory layout:
    vector  : 0xffff0000 - 0xffff1000   (   4 kB)
    fixmap  : 0xfff00000 - 0xfffe0000   ( 896 kB)
    DMA     : 0xffc00000 - 0xffe00000   (   2 MB)
    vmalloc : 0xd0800000 - 0xe0000000   ( 248 MB)
    lowmem  : 0xc0000000 - 0xd0000000   ( 256 MB)
    modules : 0xbf000000 - 0xc0000000   (  16 MB)
      .init : 0xc0008000 - 0xc0021000   ( 100 kB)
      .text : 0xc0021000 - 0xc02a9000   (2592 kB)
      .data : 0xc02c0000 - 0xc02d4d20   (  84 kB)
<6>Hierarchical RCU implementation.
<6>     RCU-based detection of stalled CPUs is disabled.
<6>     Verbose stalled-CPUs detection is disabled.
<6>NR_IRQS:96

Console: colour dummy device 80x30
<6>console [tty0] enabled
<6>Calibrating delay loop... <4>Bad IRQ3224117184
<1>Unhandled fault: alignment exception (0x801) at 0xfc200087
<0>Internal error: : 801 [#1] PREEMPT
<0>last sysfs file:
Modules linked in:
CPU: 0    Not tainted  (2.6.35-rc3 #12)
PC is at puppy_irq_mask+0x2c/0x34
LR is at handle_level_irq+0x3c/0x170
pc : []    lr : []    psr: 600001d3
sp : c02c1f58  ip : cfc07220  fp : 00000000
r10: 0000001f  r9 : c02c0000  r8 : 00000002
r7 : 00000003  r6 : 00000003  r5 : 00000000  r4 : c02c64d4
r3 : fc200087  r2 : 00000001  r1 : c02c64d4  r0 : 00000008
Flags: nZCv  IRQs off  FIQs off  Mode SVC_32  ISA ARM  Segment kernel
Control: 10c5387f  Table: 80004019  DAC: 00000017
<0>Process swapper (pid: 0, stack limit = 0xc02c0268)
<0>Stack: (0xc02c1f58 to 0xc02c2000)
<0>1f40:                                                       00000003 00000000
<0>1f60: c001bce8 c0021078 60000153 ffffffff c02c1fac c0021ae4 00002000 c02c1f30
<0>1f80: ffff8ad0 ffff8ad0 c02c5718 c02c3938 c001bce8 c02c3ad0 8001aaa4 411fc083
<0>1fa0: 0000001f 00000000 cfc07254 c02c1fc0 c0019c08 c0019c14 60000153 ffffffff
<0>1fc0: c02d4da0 c001b44c c001bce8 c02c3ad0 8001aaa4 c0008b04 c0008660 00000000
<0>1fe0: 00000000 c001bce8 10c53c7d c02d50b0 c001bce4 80008034 00000000 00000000
[] (puppy_irq_mask+0x2c/0x34) from [] (handle_level_irq+0x3c                                                                                                             /0x170)
[] (handle_level_irq+0x3c/0x170) from [] (asm_do_IRQ+0x78/0x                                                                                                             8c)
[] (asm_do_IRQ+0x78/0x8c) from [] (__irq_svc+0x44/0x78)
Exception stack(0xc02c1f78 to 0xc02c1fc0)
1f60:                                                       00002000 c02c1f30
1f80: ffff8ad0 ffff8ad0 c02c5718 c02c3938 c001bce8 c02c3ad0 8001aaa4 411fc083
1fa0: 0000001f 00000000 cfc07254 c02c1fc0 c0019c08 c0019c14 60000153 ffffffff
[] (__irq_svc+0x44/0x78) from [] (calibrate_delay+0xbc/0x1e4                                                                                                             )
[] (calibrate_delay+0xbc/0x1e4) from [] (start_kernel+0x228/                                                                                                             0x27c)
[] (start_kernel+0x228/0x27c) from [<80008034>] (0x80008034)
<0>Code: e203340f e0823003 e3a02001 e1a00012 (e5830000)
<4>Bad IRQ3224116728
<4>Bad IRQ65542
<4>Bad IRQ65542
<4>Bad IRQ65542
<4>Bad IRQ65542
<4>Bad IRQ65542
<4>Bad IRQ65542
<4>Bad IRQ65542
<4>Bad IRQ65542




Next steps, configure GPT for 1 ms.
Mapping GPT interrupt with proper interrupt handler. A lot of interrupt handling study to be done here!