📄 basic_exception_handling.html
字号:
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"><html><head> <title></title> <link rel="stylesheet" media="screen" type="text/css" href="./style.css" /> <link rel="stylesheet" media="screen" type="text/css" href="./design.css" /> <link rel="stylesheet" media="print" type="text/css" href="./print.css" /> <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /></head><body><a href=start.html>start</a></br><div class="toc"><div class="tocheader toctoggle" id="toc__header">Table of Contents</div><div id="toc__inside"><ul class="toc"><li class="clear"><ul class="toc"><li class="level2"><div class="li"><span class="li"><a href="#exceptions" class="toc">Exceptions</a></span></div><ul class="toc"><li class="level3"><div class="li"><span class="li"><a href="#interrupt_types" class="toc">Interrupt Types</a></span></div></li><li class="level3"><div class="li"><span class="li"><a href="#interrupt_numbers" class="toc">Interrupt Numbers</a></span></div></li></ul></li></ul></li></ul></div></div><h2><a name="exceptions" id="exceptions">Exceptions</a></h2><div class="level2"><p> The uClinux system runs on exceptions. If this would not true it would act like a brick. Interrupts and exceptions are the way the system responds to real world events including the timer tick. THe list of exceptions that are managed include </p><ul><li class="level1"><div class="li"> external interrupts</div></li><li class="level1"><div class="li"> system timer </div></li><li class="level1"><div class="li"> access errors</div></li><li class="level1"><div class="li"> soft interrupts</div></li></ul><p>The Exception handling is contained in these files </p><ul><li class="level1"><div class="li"> linux-2.6.x/arch/blackfin/mach-common/entry.S</div></li><li class="level1"><div class="li"> linux-2.6.x/arch/blackfin/mach-common/interrupt.S</div></li></ul><p> The vectors are set up in a C file <strong>linux-2.6.x/arch/blackfin/kernel/traps.c</strong></p><pre class="code c"><span class="coMULTI">/* Initiate the event table handler */</span><span class="kw4">void</span> __init trap_init <span class="br0">(</span><span class="kw4">void</span><span class="br0">)</span><span class="br0">{</span> __builtin_bfin_csync<span class="br0">(</span><span class="br0">)</span>; *pEVT3= trap; __builtin_bfin_csync<span class="br0">(</span><span class="br0">)</span>; *pEVT14 = evt_system_call; __builtin_bfin_csync<span class="br0">(</span><span class="br0">)</span>; *pEVT15 = evt_soft_int1; __builtin_bfin_csync<span class="br0">(</span><span class="br0">)</span>;<span class="br0">}</span> </pre><p>And here in <strong>linux-2.6.x/arch/blackfin/mach-common/ints-priority-sc.c</strong></p><pre class="code c"><span class="kw4">int</span> __init init_arch_irq<span class="br0">(</span><span class="kw4">void</span><span class="br0">)</span><span class="br0">{</span> <span class="kw4">int</span> irq; <span class="kw4">unsigned</span> <span class="kw4">long</span> ilat = <span class="nu0">0</span>; <span class="coMULTI">/* Disable all the peripheral intrs - page 4-29 HW Ref manual */</span> *pSIC_IMASK = SIC_UNMASK_ALL; __builtin_bfin_ssync<span class="br0">(</span><span class="br0">)</span>; local_irq_disable<span class="br0">(</span><span class="br0">)</span>; <span class="co2">#ifndef CONFIG_KGDB</span> *pEVT0 = evt_nmi;<span class="co2">#endif</span> *pEVT2 = evt_evt2; *pEVT3 = trap; *pEVT5 = evt_ivhw; *pEVT6 = evt_timer; *pEVT7 = evt_evt7; *pEVT8 = evt_evt8; *pEVT9 = evt_evt9; *pEVT10 = evt_evt10; *pEVT11 = evt_evt11; *pEVT12 = evt_evt12; *pEVT13 = evt_evt13; *pEVT14 = evt_system_call; *pEVT15 = evt_soft_int1; __builtin_bfin_csync<span class="br0">(</span><span class="br0">)</span>; </pre><p>NOTE there is some setup duplication here.</p><p>Most of the user interrupts are in the range 7-13 and are handled by dedicated service routines. evt_evtx where x ranges from 7 to 13.</p><p> These service routines are found in <strong>linux-2.6.x/arch/blackfin/mach-common/interrupt.S</strong>.</p><p>Here is an example </p><pre class="code c">* interrupt routine <span class="kw1">for</span> evt7 - <span class="nu0">7</span> */ENTRY<span class="br0">(</span>evt_evt7<span class="br0">)</span> SAVE_CONTEXT r0 = EVT_IVG7_P; r1 = sp; SP += <span class="nu0">-12</span>; call do_irq; SP += <span class="nu0">12</span>; RESTORE_CONTEXT rti; </pre><p> This code records the source of the interrupt and calls a common function to service the interrupt</p><p>The <strong>do_irq</strong> function is in <strong>linux-2.6.x/arch/blackfin/mach-common/ints-priority-sc.c</strong>. Each interrupt device can be assigned to a specific interrupt level ( 7-13 ). Each interrupt device will have a Linux interrupt number. The <strong>do_irq</strong> discovers the actual interrupting source and hence the <strong>Interrupt Number</strong> allocated to the interrupt source and then calls <strong>asm_do_IRQ(vec, fp)</strong>.</p><p> This code is in <strong>linux-2.6.x/arch/blackfin/kernel/irqchip.c</strong></p><p> The final service code is here.</p><pre class="code c"><span class="kw4">static</span> <span class="kw4">int</span>__do_irq<span class="br0">(</span><span class="kw4">unsigned</span> <span class="kw4">int</span> irq, <span class="kw4">struct</span> irqaction *action, <span class="kw4">struct</span> pt_regs *regs<span class="br0">)</span><span class="br0">{</span> <span class="kw4">unsigned</span> <span class="kw4">int</span> status; <span class="kw4">int</span> retval = <span class="nu0">0</span>; spin_unlock<span class="br0">(</span>&irq_controller_lock<span class="br0">)</span>; <span class="kw1">if</span> <span class="br0">(</span>!<span class="br0">(</span>action->flags & SA_INTERRUPT<span class="br0">)</span><span class="br0">)</span> <span class="br0">{</span> local_irq_enable<span class="br0">(</span><span class="br0">)</span>; <span class="br0">}</span> status = <span class="nu0">0</span>; <span class="kw1">do</span> <span class="br0">{</span> status |= action->flags; retval |= action->handler<span class="br0">(</span>irq, action->dev_id, regs<span class="br0">)</span>; action = action->next; <span class="br0">}</span> <span class="kw1">while</span> <span class="br0">(</span>action<span class="br0">)</span>; <span class="kw1">if</span> <span class="br0">(</span>status & SA_SAMPLE_RANDOM<span class="br0">)</span> add_interrupt_randomness<span class="br0">(</span>irq<span class="br0">)</span>; spin_lock_irq<span class="br0">(</span>&irq_controller_lock<span class="br0">)</span>; <span class="kw1">return</span> retval;<span class="br0">}</span></pre><p> The timer is an exception</p><pre class="code c"> ENTRY<span class="br0">(</span>evt_timer<span class="br0">)</span> SAVE_CONTEXT p2.<span class="me1">l</span> = lo<span class="br0">(</span>IPEND<span class="br0">)</span>; p2.<span class="me1">h</span> = hi<span class="br0">(</span>IPEND<span class="br0">)</span>; r0 = <span class="br0">[</span>p2<span class="br0">]</span>; <span class="coMULTI">/* Read current IPEND */</span> csync; <span class="br0">[</span>sp + PT_IPEND<span class="br0">]</span> = r0; <span class="coMULTI">/* Store IPEND */</span> r0 = IRQ_CORETMR; r1 = sp; SP += <span class="nu0">-12</span>; call timer_interrupt; SP += <span class="nu0">12</span>; call return_from_int; RESTORE_CONTEXT rti; </pre></div><!-- SECTION [1-3951] --><h3><a name="interrupt_types" id="interrupt_types">Interrupt Types</a></h3><div class="level3"><p> Different interrupt types can be define to allow generic interrupt behaviour. </p><ul><li class="level1"><div class="li"> Simple - the user handler does ack, clear , mask and unmask</div></li><li class="level1"><div class="li"> Edge - dont mask and allow it to trigger while the service is running </div></li><li class="level1"><div class="li"> Level - mask and disable then service</div></li></ul><p> For any given irq the required handler can be chosen using the <strong>set_irq_handler</strong> function</p><pre class="code c"> set_irq_handler<span class="br0">(</span>irq, do_simple_IRQ<span class="br0">)</span>; set_irq_handler<span class="br0">(</span>irq, do_level_IRQ<span class="br0">)</span>; set_irq_handler<span class="br0">(</span>irq, do_edge_IRQ<span class="br0">)</span>; </pre><p>You can add your own handler if needed just use the code for one of the existing handlers a an example.</p></div><!-- SECTION [3952-4576] --><h3><a name="interrupt_numbers" id="interrupt_numbers">Interrupt Numbers</a></h3><div class="level3"><p> uClinux works on an interrupt number assigned to a device these are defined in <strong>linux-2.6.x/include/asm-blackfin/mach-bf533/irq.h</strong>. The default layout is shown here.</p><p>NOTE The Levels of each interrupt can be reassigned during kerenl configuration.</p><pre class="code c"><span class="coMULTI">/* * Interrupt source definitions Event Source Core Event NameCore Emulation ** Events (highest priority) EMU 0 Reset RST 1 NMI NMI 2 Exception EVX 3 Reserved -- 4 Hardware Error IVHW 5 Core Timer IVTMR 6 * PLL Wakeup Interrupt IVG7 7 DMA Error (generic) IVG7 8 PPI Error Interrupt IVG7 9 SPORT0 Error Interrupt IVG7 10 SPORT1 Error Interrupt IVG7 11 SPI Error Interrupt IVG7 12 UART Error Interrupt IVG7 13 RTC Interrupt IVG8 14 DMA0 Interrupt (PPI) IVG8 15 DMA1 (SPORT0 RX) IVG9 16 DMA2 (SPORT0 TX) IVG9 17 DMA3 (SPORT1 RX) IVG9 18 DMA4 (SPORT1 TX) IVG9 19 DMA5 (PPI) IVG10 20 DMA6 (UART RX) IVG10 21 DMA7 (UART TX) IVG10 22 Timer0 IVG11 23 Timer1 IVG11 24 Timer2 IVG11 25 PF Interrupt A IVG12 26 PF Interrupt B IVG12 27 DMA8/9 Interrupt IVG13 28 DMA10/11 Interrupt IVG13 29 Watchdog Timer IVG13 30 Software Interrupt 1 IVG14 31 Software Interrupt 2 -- (lowest priority) IVG15 32 * </span></pre></div><!-- SECTION [4577-] --></body></html>
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -