Exynos4412 中断处理流程详解

 Linux 中,当外设触发中断后,大体处理流程如下:

a -- 具体CPU architecture相关的模块会进行现场保护,然后调用machine driver对应的中断处理handler;

b -- machine driver对应的中断处理handler中会根据硬件的信息获取HW interrupt ID,并且通过irq domain模块翻译成IRQ number;

c --  调用该IRQ number 对应的high level irq event handler,在这个high level的handler中,会通过和interupt controller交互,进行中断处理的flow control(处理中断的嵌套、抢占等),当然最终会遍历该中断描述符的IRQ action list,调用外设的specific handler来处理该中断;

d -- 具体CPU architecture相关的模块会进行现场恢复;

     

        总结下来,整个过程可以分为三部分:1、硬件处理部分;2、汇编处理部分;3、C 处理部分;

       下面我们来追踪一下代码,了解当中断发生时,Linux 是如何处理的,前面的一些中断初始化部分就不再这里详述了,下面开始具体分析:


一、硬件处理部分

        当一切准备好之后,一旦打开处理器的全局中断就可以处理来自外设的各种中断事件了。

        当外设(SOC内部或者外部都可以)检测到了中断事件,就会通过interrupt requestion line上的电平或者边沿(上升沿或者下降沿或者both)通知到该外设连接到的那个中断控制器,而中断控制器就会在多个处理器中选择一个,并把该中断通过IRQ(或者FIQ,本文不讨论FIQ的情况)分发给该processor。

        ARM处理器感知到了中断事件后,会进行下面一系列的动作(硬件处理部分):

1、切换处理器模式

       修改 CPSR 寄存器中的 M[4:0],切换处理器模式位 IRQ Mode(这里M[4:0] 所添值为 10010);

2、保护现场

      保存发生中断时,CPSR值与PC值(为恢复现场做准备);这里要注意,此时中断可能发生在 usr mode (用户空间),也可能发生在 SVC mode(内核空间);

3、mask IRQ exception

      关闭IRQ中断,也就是设定CPSR.I = 1;

4、设定PC值为IRQ exception vector

       实现向异常向量表的跳转,ARM处理器会跳转到IRQ的exception vector地址,到这硬件所做的工作就结束了,下面就是软件行为了。


       软件处理部分流程如下:



       可以看到 Vetor_irq 是汇编部分入口点,而Asm_do_irq 是C 部分入口点,下面分析Vetor_irq 向 Asm_do_irq 跳转过程


二、汇编部分

        前面硬件部分结束后,跳转到相应的异常中断处理程序处执行,对于ARMv7向量表普遍是0xFFFF0018 ,而对于低向量PC=0x00000018   

        假设在用户空间时,产生了外部硬件中断,这个时候的会跳转到异常向量表,向量表(vector table)的代码如下

【arch/arm/kernel/entry-armv.S】

[cpp] view plaincopy
在CODE上查看代码片派生到我的代码片
  1. __vectors_start:---------------〉在中断向量表被拷贝后,该地址就是0xffff0000.    
  2.  ARM( swi SYS_ERROR0 )    
  3.  THUMB( svc #0 )    
  4.  THUMB( nop )    
  5. W(b) vector_und + stubs_offset    
  6. W(ldr) pc, .LCvswi + stubs_offset    
  7. W(b) vector_pabt + stubs_offset    
  8. W(b) vector_dabt + stubs_offset    
  9. W(b) vector_addrexcptn + stubs_offset    
  10. W(b)vector_irq + stubs_offset----------〉当外部中断产生时,pc直接指向这个地址。    
  11. W(b) vector_fiq + stubs_offset    
  12. .globl __vectors_end    

1、IRQ mode中的处理 (vector table --- > vector_irq )

      IRQ mode的处理都在vector_irq中,vector_stub是一个宏,定义如下:

[cpp] view plaincopy
在CODE上查看代码片派生到我的代码片
  1. /*  
  2.  * Vector stubs.  
  3.  *  
  4.  * This code is copied to 0xffff0200 so we can use branches in the  
  5.  * vectors, rather than ldr's.  Note that this code must not  
  6.  * exceed 0x300 bytes.  
  7.  *  
  8.  * Common stub entry macro:  
  9.  *   Enter in IRQ mode, spsr = SVC/USR CPSR, lr = SVC/USR PC  
  10.  *  
  11.  * SP points to a minimal amount of processor-private memory, the address  
  12.  * of which is copied into r0 for the mode specific abort handler.  
  13.  */    
  14.     .macro  vector_stub, name, mode, correction=0    
  15.     .align  5    
  16.     
  17. vector_\name:    
  18.     .if \correction    
  19.     sub lr, lr, #\correction  //因为硬件处理器是将当前指令的下两条指令的地址存储在lr寄存器中,所以这里需要减4,让他指向被中断指令的下一条,这样当中断被恢复时,可以继续被中断的指令继续执行。    
  20.     .endif    //需要注意的是,这个时候的lr寄存器,已经是irq模式下的私有寄存器了,在中断产生时,硬件处理器已经自动为他赋了值。    
  21.     
  22.     @    
  23.     @ Save r0, lr_<exception> (parent PC) and spsr_<exception>    
  24.     @ (parent CPSR)    
  25.     @    
  26.     stmia   sp, {r0, lr}        @ save r0, lr//保存r0和lr寄存器,即被中断的下一条指令    
  27.     mrs lr, spsr    
  28.     str lr, [sp, #8]        @ save spsr    
  29.     
  30.     @    
  31.     @ Prepare for SVC32 mode.  IRQs remain disabled.//准备从中断模式切换到管理模式,不同的模式,对应各自不同的堆栈。    
  32.     @    
  33.     mrs r0, cpsr        
  34.     eor r0, r0, #(\mode ^ SVC_MODE | PSR_ISETSTATE)    
  35.     msr spsr_cxsf, r0    
  36.     
  37.     @    
  38.     @ the branch table must immediately follow this code    
  39.     @    
  40.     and lr, lr, #0x0f           //获取被中断前,处理器所处的模式    
  41.  THUMB( adr r0, 1f          )    
  42.  THUMB( ldr lr, [r0, lr, lsl #2]    )    
  43.     mov r0, sp  //让r0寄存器指向中断模式下堆栈的基地址    
  44.  ARM(   ldr lr, [pc, lr, lsl #2]    )    
  45.     movs    pc, lr          @ branch to handler in SVC mode,同时将中断模式下的spsr_irq(irq私有的)赋值给cpsr(该寄存器所有模式共享)    
  46. ENDPROC(vector_\name)  
从这可以看出 vector_stub 的使用方法:

       vector_stub, name, mode, correction=0

上面这段究竟做了些什么呢?

(1)我们期望在栈上保存发生中断时候的硬件现场(HW context),这里就包括ARM的core register。上一章我们已经了解到,当发生IRQ中断的时候,lr中保存了发生中断的PC+4,如果减去4的话,得到的就是发生中断那一点的PC值。

(2)当前是IRQ mode,SP_irq在初始化的时候已经设定(12个字节)。在irq mode的stack上,依次保存了发生中断那一点的r0值、PC值以及CPSR值(具体操作是通过spsr进行的,其实硬件已经帮我们保存了CPSR到SPSR中了)。为何要保存r0值?因为随后的代码要使用r0寄存器,因此我们要把r0放到栈上,只有这样才能完完全全恢复硬件现场。

(3)可怜的IRQ mode稍纵即逝,这段代码就是准备将ARM推送到SVC mode。如何准备?其实就是修改SPSR的值,SPSR不是CPSR,不会引起processor mode的切换(毕竟这一步只是准备而已)。

(4)很多异常处理的代码返回的时候都是使用了stack相关的操作,这里没有。“movs pc, lr ”指令除了字面上意思(把lr的值付给pc),还有一个
隐含的操作(movs中‘s’的含义):把SPSR copy到CPSR,从而实现了模式的切换

这里有个问题:中断为什么必须进入svc模式

一个最重要原因是:如果一个中断模式(例如从usr进入irq模式,在irq模式中)中重新允许了中断,并且在这个中断例程中使用了BL指令调用子程序,BL指令会自动将子程序返回地址保存到当前模式的sp(即r14_irq)中,这个地址随后会被在当前模式下产生的中断所破坏,因为产生中断时CPU会将当前模式的PC保存到r14_irq,这样就把刚刚保存的子程序返回地址冲掉。为了避免这种情况,中断例程应该切换到SVC或者系统模式,这样的话,BL指令可以使用r14_svc来保存子程序的返回地址


2、vector table --- > vector_irq  ---> vector _stub

对于IRQ Mode 则 vector_stub, irq, IRQ_MODE, 4   

[cpp] view plaincopy
在CODE上查看代码片派生到我的代码片
  1. __stubs_start:    
  2. /*  
  3.  * Interrupt dispatcher  
  4.  */    
  5. vector_stub irq, IRQ_MODE, 4  //减去4,确保返回发生中断之后的那条指令  
  6.     
  7.     
  8. .long __irq_usr@  0  (USR_26 / USR_32)  //从用户态进入中断的处理函数 base address + 0   
  9. .long __irq_invalid@  1  (FIQ_26 / FIQ_32)    
  10. .long __irq_invalid@  2  (IRQ_26 / IRQ_32)    
  11. .long __irq_svc@  3  (SVC_26 / SVC_32)  //从SVC进入中断的处理函数 base address + 12  
  12. .long __irq_invalid@  4    
  13. .long __irq_invalid@  5    
  14. .long __irq_invalid@  6    
  15. .long __irq_invalid@  7    
  16. .long __irq_invalid@  8    
  17. .long __irq_invalid@  9    
  18. .long __irq_invalid@  a    
  19. .long __irq_invalid@  b    
  20. .long __irq_invalid@  c    
  21. .long __irq_invalid@  d    
  22. .long __irq_invalid@  e    
  23. .long __irq_invalid@  f    

这里根据被中断时,处理器模式的不同,分别跳转到__irq_usr和__irq_svc两个分支。


3、vector table --- > vector_irq  ---> vector _stub ---> __irq_usr

在这里我们以__irq_usr为例来说明:

[cpp] view plaincopy
在CODE上查看代码片派生到我的代码片
  1. __irq_usr:    
  2.     usr_entry       //进行中断前的硬件上下文的保存    
  3.     kuser_cmpxchg_check    
  4.     irq_handler    
  5.     get_thread_info tsk//获取被中断的用户进程或内核线程所对应的内核栈所对应的thread info结构。    
  6.     mov why, #0    
  7.     b   ret_to_user_from_irq//恢复被中断时的上下文,然后继续被中断的进程或线程的执行    
  8.  UNWIND(.fnend      )    
  9. ENDPROC(__irq_usr)  


4、vector table --- > vector_irq  ---> vector _stub ---> __irq_usr ---> usr_entry

usr_entry展开如下:
[cpp] view plaincopy
在CODE上查看代码片派生到我的代码片
  1. .macro  usr_entry    
  2. UNWIND(.fnstart )    
  3. UNWIND(.cantunwind  )   @ don't unwind the user space    
  4. sub sp, sp, #S_FRAME_SIZE   // #S_FRAME_SIZE的值为72    
  5. ARM(    stmib   sp, {r1 - r12}  )      //尽管当前是处于管理模式,但由于svc和usr的r0-r12是公共的,所以相当于保存用户模式的r1-r12寄存器    
  6. THUMB(  stmia   sp, {r0 - r12}  )    
  7.     
  8. ldmia   r0, {r3 - r5}          //将之前保存在中断模式堆栈中的r0_usr,lr,spsr分别存储到r3-r5中    
  9. add r0, sp, #S_PC       @ here for interlock avoidance #S_PC=60    
  10. mov r6, #-1         @  ""  ""     ""        ""    
  11.     
  12. str r3, [sp]        @ save the "real" r0 copied    
  13.                 @ from the exception stack    
  14.     
  15. @    
  16. @ We are now ready to fill in the remaining blanks on the stack:    
  17. @    
  18. @  r4 - lr_<exception>, already fixed up for correct return/restart    
  19. @  r5 - spsr_<exception>    
  20. @  r6 - orig_r0 (see pt_regs definition in ptrace.h)    
  21. @    
  22. @ Also, separately save sp_usr and lr_usr    
  23. @    
  24. stmia   r0, {r4 - r6}    
  25. ARM(    stmdb   r0, {sp, lr}^           )//保存用户模式下的sp_usr,lr_usr    
  26. THUMB(  store_user_sp_lr r0, r1, S_SP - S_PC    )    
  27.     
  28. @    
  29. @ Enable the alignment trap while in kernel mode    
  30. @    
  31. alignment_trap r0    
  32.     
  33. @    
  34. @ Clear FP to mark the first stack frame    
  35. @    
  36. zero_fp    
  37.     
  38. ifdef CONFIG_IRQSOFF_TRACER    
  39. bl  trace_hardirqs_off    
  40. endif    
  41. .endm    

      代码执行到这里的时候,ARM处理已经切换到了【SVC mode】。一旦进入SVC mode,ARM处理器看到的寄存器已经发生变化,这里的sp已经变成了sp_svc了。因此,后续的压栈操作都是压入了发生中断那一刻的进程的(或者内核线程)内核栈(svc mode栈)。

     此时的管理模式的内核栈分布如下:

       需要说明的是:上图中的lr_irq即为用户模式下被中断指令的下一条指令,spsr_irq即为用户模式下被中断时的cpsr寄存器。


5、vector table --- > vector_irq  ---> vector _stub ---> __irq_usr ---> (usr_entry  ---> irq_handler )

       usr_entry 结束后,会执行 irq_handler

irq_handler的实现过程 arch\arm\kernel\entry-armv.S

[cpp] view plaincopy
在CODE上查看代码片派生到我的代码片
  1. .macro irq_handler  
  2.               get_irqnr_preamble r5, lr  
  3.               @在include/asm/arch-s3c2410/entry-macro.s中定义了宏get_irqnr_preamble为空操作,什么都不做  
  4.               1: get_irqnr_and_base r0, r6, r5, lr @判断中断号,通过R0返回,3.5节有实现过程   
  5.               movne r1, sp  
  6.               @  
  7.               @ routine called with r0 = irq number, r1 = struct pt_regs *  
  8.               @  
  9.               adrne lr, 1b  
  10.               bne asm_do_IRQ @进入中断处理。   
  11.        ……   
  12.               .endm  

可以看到 bne asm_do_IRQ @进入中断处理  泪奔~~o(>_<)o ~~ 终于到了asm_do_IRQ

可以看到整个跳转过程:

vector table --- > vector_irq  --->vector_stub, irq, IRQ_MODE, 4 ---> __irq_usr ---> usr_entry  ---> irq_handler --->asm_do_IRQ 



三、C语言处理部分

1、 asm_do_IRQ

        asm_do_IRQ实现过程,arch/arm/kernel/irq.c 

[cpp] view plaincopy
在CODE上查看代码片派生到我的代码片
  1.  * asm_do_IRQ is the interface to be used from assembly code.  
  2.  */  
  3. asmlinkage void __exception_irq_entry  
  4. asm_do_IRQ(unsigned int irq, struct pt_regs *regs)  
  5. {  
  6.     handle_IRQ(irq, regs);  
  7. }  

[cpp] view plaincopy
在CODE上查看代码片派生到我的代码片
  1. <span style="font-family: Arial, Helvetica, sans-serif;">其中关键一步handle_IRQ(irq, regs)</span>  
 

2、handle_IRQ(irq, regs)

[cpp] view plaincopy
在CODE上查看代码片派生到我的代码片
  1. /* 
  2.  * handle_IRQ handles all hardware IRQ's.  Decoded IRQs should 
  3.  * not come via this function.  Instead, they should provide their 
  4.  * own 'handler'.  Used by platform code implementing C-based 1st 
  5.  * level decoding. 
  6.  */  
  7. void handle_IRQ(unsigned int irq, struct pt_regs *regs)  
  8. {  
  9.     struct pt_regs *old_regs = set_irq_regs(regs);  
  10.   
  11.     irq_enter();  
  12.   
  13.     /* 
  14.      * Some hardware gives randomly wrong interrupts.  Rather 
  15.      * than crashing, do something sensible. 
  16.      */  
  17.     if (unlikely(irq >= nr_irqs)) {  
  18.         if (printk_ratelimit())  
  19.             printk(KERN_WARNING "Bad IRQ%u\n", irq);  
  20.         ack_bad_irq(irq);  
  21.     } else {  
  22.         generic_handle_irq(irq);  
  23.     }  
  24.   
  25.     irq_exit();  
  26.     set_irq_regs(old_regs);  
  27. }  

主要调用generic_handle_irq(irq)


3、generic_handle_irq(irq)

[cpp] view plaincopy
在CODE上查看代码片派生到我的代码片
  1. include/linux/irq.h  
  2. static inline void generic_handle_irq_desc(unsigned int irq, struct irq_desc *desc)  
  3. {  
  4. #ifdef CONFIG_GENERIC_HARDIRQS_NO__DO_IRQ  
  5.         desc->handle_irq(irq, desc);  
  6. #else  
  7.         if (likely(desc->handle_irq))  
  8.                desc->handle_irq(irq, desc);  
  9.         else  
  10.                __do_IRQ(irq);  
  11. #endif  
  12. }  
  13.   
  14. static inline void generic_handle_irq(unsigned int irq)  
  15. {  
  16.         generic_handle_irq_desc(irq, irq_to_desc(irq));  
  17. }  
generic_handle_irq调用前面定义的generic_handle_irq_desc


4、generic_handle_irq_des

[cpp] view plaincopy
在CODE上查看代码片派生到我的代码片
  1. static inline void generic_handle_irq_desc(unsigned int irq, struct irq_desc *desc)  
  2.   
  3. desc->handle_irq(irq, desc);  

而 generic_handle_irq_desc也没做什么,调用desc——>handle_irq</strong>,这个函数就是irq_desc中的成员


5、irq_desc结构体      

       Linux内核将所有中断统一编号,使用irq_desc结构来描述中断:每个数组项对应一个中断(也可能是一组中断,它们使用共同的中断号),里面记录了中断的名称,中断状态,中断标记,并提供硬件访问函数(清除,屏蔽,使能中断),提供了这个中断的处理函数的入口,通过它可以调用用户注册的中断处理函数

[cpp] view plaincopy
在CODE上查看代码片派生到我的代码片
  1. include/linux/irq.h  
  2. {  
  3.     .........  
  4.   
  5.     irq_flow_handler_t handle_irq;   //当前的中断处理函数入口  
  6.     struct irq_chip *chip;       //底层的硬件访问  
  7.       
  8.     ..........  
  9.   
  10.     struct irqaction *action; //用户提供的中断处理函数链表  
  11.     unsigned int status; //IRQ状态  
  12.   
  13.     ...........  
  14.   
  15.     const char *name;     //中断名称  
  16. } ____cacheline_internodealigned_in_smp;  

    Handle_irq是这个或者这组中断的处理函数入口

    这里调用desc->handle_irq分为俩种情况,一是单独的中断号的,一是共享中断号的,俩者的区别在于后者需要先判断是共享中断的中的哪一个然后再真正的去调用handle_irq,所以我这里分析一下单独中断号的处理流程,共享中断也是一样可以分析。

        我们分析一个具体的,以外部中断为例

[cpp] view plaincopy
在CODE上查看代码片派生到我的代码片
  1. for (irqno = IRQ_EINT0; irqno <= IRQ_EINT3; irqno++) {  
  2.                irqdbf("registering irq %d (ext int)\n", irqno);  
  3.                set_irq_chip(irqno, &s3c_irq_eint0t4);  
  4.                set_irq_handler(irqno, handle_edge_irq);  
  5.                set_irq_flags(irqno, IRQF_VALID);  
  6.         }  
       上面代码我们看到,set_irq_handler的值是handler_edge_irq ,这里是处理边沿触发的中断函数,当然还有电平触发方式的中断(handler_level_irq),继续看代码
[cpp] view plaincopy
在CODE上查看代码片派生到我的代码片
  1. kernel/irq/chip.c  
  2. void  
  3. handle_edge_irq(unsigned int irq, struct irq_desc *desc)  
  4. {  
  5.         spin_lock(&desc->lock);         上锁  
  6.    
  7.         desc->status &= ~(IRQ_REPLAY | IRQ_WAITING);   
  8.    
  9.         /* 
  10.          * If we're currently running this IRQ, or its disabled, 
  11.          * we shouldn't process the IRQ. Mark it pending, handle 
  12.          * the necessary masking and go out 
  13.          */  
  14.         if (unlikely((desc->status & (IRQ_INPROGRESS | IRQ_DISABLED)) ||   判断  
  15.                    !desc->action)) {  
  16.                desc->status |= (IRQ_PENDING | IRQ_MASKED);  
  17.                mask_ack_irq(desc, irq);   屏蔽并清除中断  
  18.                goto out_unlock;  
  19.         }  
  20.         kstat_incr_irqs_this_cpu(irq, desc); 中断统计计数  
  21.    
  22.         /* Start handling the irq */  
  23.         if (desc->chip->ack)      应答中断  
  24.                desc->chip->ack(irq);  
  25.    
  26.         /* Mark the IRQ currently in progress.*/  
  27.         desc->status |= IRQ_INPROGRESS;   标记中断状态  
  28.    
  29.         do {  
  30.                struct irqaction *action = desc->action;  
  31.                irqreturn_t action_ret;  
  32.    
  33.                if (unlikely(!action)) {  
  34.                        desc->chip->mask(irq);  
  35.                        goto out_unlock;  
  36.                }  
  37.    
  38.                /* 
  39.                 * When another irq arrived while we were handling 
  40.                 * one, we could have masked the irq. 
  41.                 * Renable it, if it was not disabled in meantime. 
  42.                 */  
  43.                if (unlikely((desc->status &  
  44.                               (IRQ_PENDING | IRQ_MASKED | IRQ_DISABLED)) ==  
  45.                              (IRQ_PENDING | IRQ_MASKED))) {  
  46.                        desc->chip->unmask(irq);  
  47.                        desc->status &= ~IRQ_MASKED;  
  48.                }  
  49.    
  50.                desc->status &= ~IRQ_PENDING;  
  51.                spin_unlock(&desc->lock);  
  52.                action_ret = handle_IRQ_event(irq, action);  处理中断,最重要的函数,注意参数,action这个参数将联系到我们的用户中断处理函数  
  53.                if (!noirqdebug)  
  54.                        note_interrupt(irq, desc, action_ret);  
  55.                spin_lock(&desc->lock);  
  56.    
  57.         } while ((desc->status & (IRQ_PENDING | IRQ_DISABLED)) == IRQ_PENDING);  
  58.    
  59.         desc->status &= ~IRQ_INPROGRESS;  
  60. out_unlock:  
  61.         spin_unlock(&desc->lock);  
  62. }  
进行追踪handle_IRQ_event()

[cpp] view plaincopy
在CODE上查看代码片派生到我的代码片
  1. kernel/irq/handle.c  
  2.                trace_irq_handler_entry(irq, action);  
  3.                ret = action->handler(irq, action->dev_id);  
  4.                trace_irq_handler_exit(irq, action, ret);  

       调用action中的handler,我们注册中断的时候注意任务就是构造一个irqaction结构并添加到irq_desc中的irqaction链表中的指针action下面。现在处理中断中我们就看到了调用了我们自己的中断处理函数来处理中断了。至此中断处理流程就结束了


总结软件部分:

asm_do_IRQ --> handle_IRQ(irq, regs)--> generic_handle_irq(irq) --> generic_handle_irq_desc --> (desc—>handle_irq ) -->handle_level_irq --> handle_irq_event---> action->handler(irq, action->dev_id)

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/402249.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Exynos4412 中断驱动开发相关问题总结

1、Linux 中如何标识一个外部中断&#xff1f; 在linux kernel中&#xff0c;我们使用下面两个ID来标识一个来自外设的中断&#xff1a; a -- IRQ number CPU需要为每一个外设中断编号&#xff0c;我们称之IRQ Number。这个IRQ number是一个虚拟的interrupt ID&#xff0c;和硬…

Exynos4412 IIC 总线驱动开发相关问题总结

一 、问题 1、IIC总线上的设备是怎么描述的&#xff1f; struct i2c_client{struct device dev;...};2、IIC总线上的驱动是怎么描述的&#xff1f; struct i2c_driver {struct device_driver driver;};3、IIC总线上的设备和驱动是怎么匹配的 1)、对于 Cortex - A8 通过driver…

sersync+rsync实现实时同步

在分布式应用中会遇到一个问题&#xff0c;就是多个服务器间的文件如何能始终保持一致。一种经典的办法是将需要保持一致的文件存储在NFS上&#xff0c;这种方法虽然简单方便但却将本来多点的应用在文件存储上又变成了单点&#xff0c;这违背了分布式应用部署的初衷。为了保留多…

Exynos4412 IIC总线驱动开发(二)—— IIC 驱动开发

前面在Exynos4412 IIC总线驱动开发&#xff08;一&#xff09;—— IIC 基础概念及驱动架构分析 中学习了IIC驱动的架构&#xff0c;下面进入我们的驱动开发过程 首先看一张代码层次图&#xff0c;有助于我们的理解 上面这些代码的展示是告诉我们&#xff1a;linux内核和芯片提…

Exynos4412 IIC总线驱动开发(一)—— IIC 基础概念及驱动架构分析

关于Exynos4412 IIC 裸机开发请看 &#xff1a;Exynos4412 裸机开发 —— IIC总线 &#xff0c;下面回顾下 IIC 基础概念 一、IIC 基础概念 IIC(Inter&#xff0d;Integrated Circuit)总线是一种由PHILIPS公司开发的两线式串行总线&#xff0c;用于连接微控制器及其外围设备。I…

Python 爬虫进阶一之爬虫框架概述

综述 爬虫入门之后&#xff0c;我们有两条路可以走。 一个是继续深入学习&#xff0c;以及关于设计模式的一些知识&#xff0c;强化 Python 相关知识&#xff0c;自己动手造轮子&#xff0c;继续为自己的爬虫增加分布式&#xff0c;多线程等功能扩展。另一条路便是学习一些优秀…

1039. 到底买不买(20)

1039. 到底买不买&#xff08;20&#xff09; 小红想买些珠子做一串自己喜欢的珠串。卖珠子的摊主有很多串五颜六色的珠串&#xff0c;但是不肯把任何一串拆散了卖。于是小红要你帮忙判断一下&#xff0c;某串珠子里是否包含了全部自己想要的珠子&#xff1f;如果是&#xff0c…

Exynos4412 ADC 设备驱动开发

具体ADC硬件知识及裸机驱动请看&#xff1a; Exynos4412裸机开发 —— A/D转换器 1、原理图如下&#xff1a; 2、相关寄存器信息 ADC_BASE 0x126C0000ADCCON 0x0000 1<<0 | 1<<14 | 0X1<<16 | 0XFF<<6ADCDLY 0x000…

Python 爬虫进阶二之 PySpider 框架安装配置

PySpider官方文档 项目地址 官方文档 安装 phantomjs PhantomJS 是一个基于 WebKit 的服务器端 JavaScript API。它全面支持 web 而不需浏览器支持&#xff0c;其快速、原生支持各种 Web 标准&#xff1a;DOM 处理、CSS 选择器、JSON、Canvas 和 SVG。 PhantomJS 可以用于页…

Exynos4412 中断驱动开发(三)—— 设备树中中断节点的创建

提到中断就必须了解到GIC&#xff0c;下面先了解一下GIC 一、GIC概念 GIC&#xff08;Generic Interrupt Controller&#xff09;是ARM公司提供的一个通用的中断控制器。GIC通过AMBA&#xff08;Advanced Microcontroller Bus Architecture&#xff09;这样的片上总线连接到一个…

Exynos4412 中断驱动开发(二)—— 中断处理流程分析

前面已经学习了中断的注册过程&#xff0c;下面由一张流程图来看一下当中断发生时的处理流程&#xff1a; 中断发生之后处理流程 a -- 具体的CPU architecture相关模块进行现场保护&#xff0c;然后调用machine driver执行对应的中断处理handler; b -- machine driver对应中断处…

Exynos4412 中断驱动开发(一)—— 中断基础及中断的注册过程

一、中断基础概念 所谓中断&#xff0c;指CPU在执行程序的过程中&#xff0c;出现了某些突发事件即待处理&#xff0c;CPU必须暂停当前的程序。转去处理突发事件&#xff0c;处理完毕后CPU又返回原程序被中断的位置并继续执行。 1、中断分类 a -- 内部中断和外部中断 根据中断的…

rubymine 调试 redmine

1、安装debase和ruby-debug-ide包。&#xff08;注意版本&#xff0c;rubymine 8.0.2下&#xff0c;bitnami下的版本需安装debase -v 0.2.1版本&#xff0c;网上有文章说用debase -v 0.2.2beta6。容易在rubymine启动调试时出现找不到ruby-debug-ide等错误提示&#xff09; 启动…

Linux 设备驱动中的 I/O模型(二)—— 异步通知和异步I/O

阻塞和非阻塞访问、poll() 函数提供了较多地解决设备访问的机制&#xff0c;但是如果有了异步通知整套机制就更加完善了。 异步通知的意思是&#xff1a;一旦设备就绪&#xff0c;则主动通知应用程序&#xff0c;这样应用程序根本就不需要查询设备状态&#xff0c;这一点非常类…

判断链表是否有环

链表有环的情况一般是链表的尾指向前面的节点而不是null&#xff0c;如head->node1->node2->node3->node4->tail->node2&#xff0c;该链表存在环。判断环是否存在可以借助两个指针&#xff0c;一个指针每次迭代只移动一步&#xff0c;第二个指针每次迭代移动…

Linux 设备驱动中的 I/O模型(一)—— 阻塞和非阻塞I/O

在前面学习网络编程时&#xff0c;曾经学过I/O模型 Linux 系统应用编程——网络编程&#xff08;I/O模型&#xff09;&#xff0c;下面学习一下I/O模型在设备驱动中的应用。 回顾一下在Unix/Linux下共有五种I/O模型&#xff0c;分别是&#xff1a; a -- 阻塞I/O b -- 非阻塞I/O…

Python 爬虫进阶六之多进程的用法

python 中的多线程其实并不是真正的多线程&#xff0c;并不能做到充分利用多核 CPU 资源。 如果想要充分利用&#xff0c;在 python 中大部分情况需要使用多进程&#xff0c;那么这个包就叫做 multiprocessing。 借助它&#xff0c;可以轻松完成从单进程到并发执行的转换。mult…

Linux 设备驱动的并发控制

Linux 设备驱动中必须要解决的一个问题是多个进程对共享的资源的并发访问&#xff0c;并发的访问会导致竞态&#xff0c;即使是经验丰富的驱动工程师也常常设计出包含并发问题bug 的驱动程序。 一、基础概念 1、Linux 并发相关基础概念 a -- 并发&#xff08;concurrency&#…

第三章:多坐标系

第一节&#xff1a;为什么要有多坐标系 当我们使用一个坐标系来描绘整个场景的时候&#xff0c;场景中的任意点都可以用该坐标系描述&#xff0c;此时如果有一只羊一遍摇动着耳朵&#xff0c;一边走&#xff0c;这个时候如果进行坐标的转换会发现异常的麻烦&#xff0c;此时如果…

Linux 设备驱动开发 —— 设备树在platform设备驱动中的使用

关与设备树的概念&#xff0c;我们在Exynos4412 内核移植&#xff08;六&#xff09;—— 设备树解析 里面已经学习过&#xff0c;下面看一下设备树在设备驱动开发中起到的作用 Device Tree是一种描述硬件的数据结构&#xff0c;设备树源(Device Tree Source)文件&#xff08;以…