精华内容
下载资源
问答
  • 内核IRQ中断向量
    千次阅读
    2019-08-01 19:45:11

    首先看一下vector_irq的定义,此每处理器数组变量,保存每个处理器上中断向量所对应的中断号,其以中断向量值为索引。系统中定义了256个中断向量。相关代码如下:

    typedef int vector_irq_t[NR_VECTORS];
    
    DEFINE_PER_CPU(vector_irq_t, vector_irq) = {
        [0 ... NR_VECTORS - 1] = VECTOR_UNDEFINED,
    };
    
    
    #define NR_VECTORS  256
    

    另一个是used_vector的定义,其为一个位图变量,用来标记系统中已经使用的中断向量。

    DECLARE_BITMAP(used_vectors, NR_VECTORS);
    

    中断向量初始化

    中断初始化入口函数init_IRQ。为支持传统的PIC类型的终端控制器,如8259,内核预留了IRQ0_VECTOR 到 IRQ15_VECTOR 共16个中断向量,分别对应IRQ号0到15。在初始化时,也不是全部预留这16个中断向量,而是根据检测到的传统PIC中断控制器所支持中断数量在预留,有可能小于16个。x86_init.irqs.intr_init()指针对应的为native_init_IRQ函数,接下来介绍。

    void __init init_IRQ(void)
    {
    
        for (i = 0; i < nr_legacy_irqs(); i++)
            per_cpu(vector_irq, 0)[IRQ0_VECTOR + i] = i;
    
        x86_init.irqs.intr_init();
    }
    

    函数apic_intr_init负责分配系统自身所需的中断向量。x86架构的IDT中断描述表可用的外部中断向量由0x20(FIRST_EXTERNAL_VECTOR)开始,其中0x80(IA32_SYSCALL_VECTOR)为系统调用所用的中断向量;0x30-0x3f共16个中断向量保留给ISA使用。interrupt函数参见文件arch/x86/kernel/entry_64.S中的定义,表示中断处理程序的入口地址,for_each_clear_bit_from循环将所有未使用的中断向量的处理程序入口设定为interrupt的相应偏移。最后对于传统的中断控制器,irq2用作两片控制器的级联。

    void __init native_init_IRQ(void)
    {
        apic_intr_init();
    
        i = FIRST_EXTERNAL_VECTOR;
        for_each_clear_bit_from(i, used_vectors, NR_VECTORS) {
            set_intr_gate(i, interrupt[i - FIRST_EXTERNAL_VECTOR]);
        }
    
        if (!acpi_ioapic && !of_ioapic)
            setup_irq(2, &irq2);
    }
    

    系统中断向量分配

    函数apic_intr_init。首先分配SMP相关的中断向量,参见函数smp_intr_init,随后是分配其他的向量。这些中断向量值由大到小分配,首先是:SPURIOUS_APIC_VECTOR(0xff),目前最小的是:LOCAL_TIMER_VECTOR(0xef)。内核中定义了变量first_system_vector表示当前系统中断向量的最小值。

    static void __init apic_intr_init(void)
    {
        smp_intr_init();
    
    #ifdef CONFIG_X86_THERMAL_VECTOR
        alloc_intr_gate(THERMAL_APIC_VECTOR, thermal_interrupt);
    }
    
    static void __init smp_intr_init(void)
    {
    #ifdef CONFIG_SMP
    #if defined(CONFIG_X86_64) || defined(CONFIG_X86_LOCAL_APIC)
        alloc_intr_gate(RESCHEDULE_VECTOR, reschedule_interrupt);
    }
    

    alloc_intr_gate宏由alloc_system_vector和set_intr_gate两个函数组成。前者为注册的系统中断向量设置used_vectors中的使用标志,并且更新系统最小向量值:first_system_vector。后者set_intr_gate函数设置处理器的IDT表。

    static inline void alloc_system_vector(int vector)
    {
        if (!test_bit(vector, used_vectors)) {
            set_bit(vector, used_vectors);
            if (first_system_vector > vector)
                first_system_vector = vector;
        } else {
            BUG();
        }
    }
    
    #define alloc_intr_gate(n, addr)                \
        do {                            \
            alloc_system_vector(n);             \
            set_intr_gate(n, addr);             \
        } while (0)
    

    外部中断向量分配

    由如下函数irq_alloc_hwirqs可见,首先调用函数__irq_alloc_descs分配中断号,内核中已经使用的中断号标记在全局位图变量allocated_irqs中,函数的第一个参数表示期望的中断号,-1表示由系统来选择中断号。系统将在allocated_irqs位图中选择一个不为零的位返回,作为新的中断号。

    函数arch_setup_hwirq负责为中断号查找合适的中断向量。注意在执行过程中出现错误的话,函数将执行回退处理,包括由函数irq_free_descs复位之前分配中断号时设置的allocated_irqs中的位。arch_teardown_hwirq函数是对应arch_setup_hwirq函数的清理函数。

    unsigned int irq_alloc_hwirqs(int cnt, int node)
    {
        int i, irq = __irq_alloc_descs(-1, 0, cnt, node, NULL);
    
        if (irq < 0)
            return 0;
    
        for (i = irq; cnt > 0; i++, cnt--) {
            if (arch_setup_hwirq(i, node))
                goto err;
    
            irq_clear_status_flags(i, _IRQ_NOREQUEST);
        }
        return irq;
    
    err:
        for (i--; i >= irq; i--) {
            irq_set_status_flags(i, _IRQ_NOREQUEST | _IRQ_NOPROBE);
            arch_teardown_hwirq(i);
        }
        irq_free_descs(irq, cnt);
        return 0;
    }
    

    arch_setup_hwirq函数的主体是由__assign_irq_vector函数完成,其定义如下。由于终端级别是由中断向量后4位决定的,而本地的APIC不能够很好的处理多个同级别的中断,所以内核以2的4次方,即16为区间,进行中断向量的分配。

    使用静态变量current_vector和current_offset分别记录当前的区间起始值和区间内偏移。第一次分配中断向量时,current_vector为33,偏移值为1,所以第一个可供分配的中断向量为34。

    static int __assign_irq_vector(int irq, struct irq_cfg *cfg, const struct cpumask *mask)
    {
        static int current_vector = FIRST_EXTERNAL_VECTOR + VECTOR_OFFSET_START;
        static int current_offset = VECTOR_OFFSET_START % 16;
    

    以下的中断向量查找由两个循环组成。第一个循环遍历中断可用的处理器列表,由APIC控制器的可用处理器列表和在线处理器列表中第一个同时置位的处理器开始,第二个循环(内部循环)遍历所有可用的中断向量vector,如果没有合适的选择,即vector的值又回到了最初的current_vector,进行第二次循环,遍历第二个可用的处理器。

    获取第二个可用处理器的算法为:1)当前分配的处理器域domain(处理器列表),与老的域值old_domain进行或操作;2)将上一步的结果和APIC处理器列表进行与操作;3)在第二步所得结果和在线处理器列表中获取第一个同时置位的处理器。此即下一个循环要遍历的处理器。

    1287     cpumask_clear(cfg->old_domain);
    1288     cpu = cpumask_first_and(mask, cpu_online_mask);
    1289     while (cpu < nr_cpu_ids) {
    1290         int new_cpu, vector, offset;
    1291
    1294         apic->vector_allocation_domain(cpu, tmp_mask, mask);
    
    1335         if (unlikely(current_vector == vector)) {
    1340             cpumask_or(cfg->old_domain, cfg->old_domain, tmp_mask);
    1345             cpumask_andnot(tmp_mask, mask, cfg->old_domain);
    1348             cpu = cpumask_first_and(tmp_mask, cpu_online_mask);
    1350             continue;
    1351         }
    

    内部的循环由标签和goto语句组成。每次遍历16长度的区间中的第一个偏移向量值,一直遍历完所有的区间。之后,当vector向量值大于最大可用向量值first_system_vector时,重新由第一个区间的第二个偏移值开始遍历。

    如果遍历的向量值没有被使用,即used_vectors位图没有置位。并且,tmp_mask中的所有有效处理器上vector_irq映射还没有被占用,表明此中断向量可用。

    1324         vector = current_vector;
    1325         offset = current_offset;
    1326 next:
    1329         vector += 16;
    1330         if (vector >= first_system_vector) {
    1331             offset = (offset + 1) % 16;
    1332             vector = FIRST_EXTERNAL_VECTOR + offset;
    1333         }
    1334
    1335         if (unlikely(current_vector == vector)) {
    1340             cpumask_or(cfg->old_domain, cfg->old_domain, tmp_mask);
    1345             cpumask_andnot(tmp_mask, mask, cfg->old_domain);
    1348             cpu = cpumask_first_and(tmp_mask, cpu_online_mask);
    1350             continue;
    1351         }
    1352
    1353         if (test_bit(vector, used_vectors))
    1355             goto next;
    1357
    1358         for_each_cpu_and(new_cpu, tmp_mask, cpu_online_mask) {
    1359             if (per_cpu(vector_irq, new_cpu)[vector] > VECTOR_UNDEFINED)
    1360                 goto next;
    1361         }
    

    成功找到可用的中断向量之后,更新静态的current_vector和current_offset的值,并更新tmp_mask中所有处理器的vector_irq中断向量和中断号映射值,写入分配的irq中断号,表明此中断向量已被占用。使用cfg中的domain成员记录有效的处理器列表。

    除去第一次申请中断向量外,系统也可能动态的调整中断向量,及为其服务的处理器列表,old_domain用来保存调整前的处理器列表,move_in_progress表示是否正处于调整期间,调整结束之后old_domain为空,move_in_progress也值为0。

    1362         /* Found one! */
    1363         current_vector = vector;
    1364         current_offset = offset;
    1365         if (cfg->vector) {
    1371             cpumask_copy(cfg->old_domain, cfg->domain);
    1374             cfg->move_in_progress = cpumask_intersects(cfg->old_domain, cpu_online_mask);
    1377         }
    
    1380         for_each_cpu_and(new_cpu, tmp_mask, cpu_online_mask)
    1381             per_cpu(vector_irq, new_cpu)[vector] = irq;
    1382         cfg->vector = vector;
    1383         cpumask_copy(cfg->domain, tmp_mask);
    1387
    1388         err = 0;
    1389         break;
    

    另外,在中断调整时,如果服务的处理器列表调整前后一致,直接跳出循环(cpumask_equal(tmp_mask, cfg->domain))。如果新的处理器列表是调整前处理器列表的子集,移除多余的处理器,并更新domain为调整之后的处理器列表。

    1294         apic->vector_allocation_domain(cpu, tmp_mask, mask);
    1295
    1296         if (cpumask_subset(tmp_mask, cfg->domain)) {
    1297             err = 0;
    
    1303             if (cpumask_equal(tmp_mask, cfg->domain))
    1304                 break;
    1305             /*
    1306              * New cpumask using the vector is a proper subset of the current in use mask. So cleanup the vector
    1308              * allocation for the members that are not used anymore.
    1309              */
    1310             cpumask_andnot(cfg->old_domain, cfg->domain, tmp_mask);
    1313
    1314             cfg->move_in_progress = cpumask_intersects(cfg->old_domain, cpu_online_mask);
    1317             cpumask_and(cfg->domain, cfg->domain, tmp_mask);
    1320
    1321             break;
    1322         }
    

    以上的介绍打乱了代码的顺序,以行号为准。

    内核版本:3.10.0

    更多相关内容
  • 但当系统中有两个程序时,例如带bootloader的系统,则应用程序的运行需要通过bootloader跳转,和bootloader相比,应用程序的地址和中断向量表地址都发生改变,如何告诉编译器来分配bootloader和应用程序在flash中的...
  • 独创了一种基于RAM中转的中断跳转方法,该方法以软件形式实现了单片机的中断向量重定位功能,实现了在应用中编程,克服了某类普通经济型单片机无法通过硬件寄存器设置中断跳转地址来实现跳转的局限性,使得这类...
  • 中断向量

    千次阅读 2019-06-26 11:11:56
    中断向量是什么

    1. 目标

    1)中断向量概念
    2)中断向量的加载
    3)中断硬件准备
    3) 中断处理服务vector_irq的定义
    4) 中断处理服务 vector_irq的处理流程
    5) 如果进入中断前是svc模式处理场景
    6)如果进入中断钱是usr模式处理场景
    内核版本:4.4.17

    2. 中断向量表

    中断向量表中保存所有中断向量的入口,__vectors_start是一个中断向量表,其中的一项:W(b) vector_irq,就是放的一个跳转指令,跳转到vector_irq。

    在arch/arm/kernel/entry-armv.S中的__vectors_start的定义如下:

    1209 __vectors_start:                                                                
    1210         W(b)    vector_rst                                                      
    1211         W(b)    vector_und                                                      
    1212         W(ldr)  pc, __vectors_start + 0x1000                                    
    1213         W(b)    vector_pabt                                                     
    1214         W(b)    vector_dabt                                                     
    1215         W(b)    vector_addrexcptn                                               
    1216         W(b)    vector_irq                    //b是跳转指令                       
    1217         W(b)    vector_fiq                                                      
    1218                                                                                 
    1219         .data    
    
    地址异常种类
    0xffff 0000复位
    0xffff 0004未定义指令
    0xffff 0008软中断(SWI)
    0xffff 000cprefetch abort
    0xffff 0010data abort
    0xffff 0014address exception
    0xffff 0018irq
    0xffff 001cfiq

    3. 中断向量加载

    arch/arm/kernel/traps.c中,early_trap_init函数中:

    802 void __init early_trap_init(void *vectors_base)                                 
    803 {                                                                               
    804 #ifndef CONFIG_CPU_V7M                                                          
    805         unsigned long vectors = (unsigned long)vectors_base;                                                                                                  
    806         extern char __stubs_start[], __stubs_end[];                             
    807         extern char __vectors_start[], __vectors_end[];                         
    808         unsigned i;                                                             
    809                                                                                 
    810         vectors_page = vectors_base;                                            
    811                                                                                 
    812         /*                                                                      
    813          * Poison the vectors page with an undefined instruction.  This         
    814          * instruction is chosen to be undefined for both ARM and Thumb         
    815          * ISAs.  The Thumb version is an undefined instruction with a          
    816          * branch back to the undefined instruction.                            
    817          */                                                                     
    818         for (i = 0; i < PAGE_SIZE / sizeof(u32); i++)                           
    819                 ((u32 *)vectors_base)[i] = 0xe7fddef1;                          
    820                                                                                 
    821         /*                                                                      
    822          * Copy the vectors, stubs and kuser helpers (in entry-armv.S)          
    823          * into the vector page, mapped at 0xffff0000, and ensure these         
    824          * are visible to the instruction stream.                               
    825          */                                                                     
    826         memcpy((void *)vectors, __vectors_start, __vectors_end - __vectors_start);
    827         memcpy((void *)vectors + 0x1000, __stubs_start, __stubs_end - __stubs_start);
    828         printk(KERN_ERR "tom __vectors_start=%x __vectors_end=%x\n",__vectors_start,__vectors_end);
    printk(KERN_ERR "tom %x %x %x %x\n",*((char *)vectors+24),*((char *)vectors+25),*((char *)vectors+26),*((char *)vectors+27));
    838         kuser_init(vectors_base);                                               
    839                                                                                 
    840         flush_icache_range(vectors, vectors + PAGE_SIZE * 2);                   
    841 #else /* ifndef CONFIG_CPU_V7M */                                               
    842         /*                                                                      
    843          * on V7-M there is no need to copy the vector table to a dedicated     
    844          * memory area. The address is configurable and so a table in the kernel
    845          * image can be used.                                                   
    846          */                                                                     
    847 #endif                                                                          
    848 }  
    

    打印信息是:

    tom __vectors_start=80630000 __vectors_end=80630020
    tom 0 4 0 ea
    

    在System.map中有__vectors_start的符号是0x80630000 ,__vectors_end是 0x80630020和打印信息一致。
    1
    W(b) vector_irq在内存的内容分别是: 0x00 0x04 0x00 0xea,这些是机器码,转换为整数是:0xea000400,0xea是跳转b的机器码,0x400是偏移量,怎么算出偏移量呢?
    在objdump -d vmlinux中输出信息中:
    123

    1. 场景是:程序中执行到0x18: b vector_irq,跳转到0x1020中的vector_irq中的偏移量怎么算?
      偏移量公式: (目标地址 - 指令地址 - 8)/ 4 = 偏移
      则: (0x1020-0x18-8)/4=0x400
      2)静态分析vmlinux中b vector_irq的机器码就是0xea00400,和内存运行时的内容一样的。

    3 vector_irq定义

    vector_stub的定义如下:

    1027         .macro  vector_stub, name, mode, correction=0   //定义vector_stub有3个参数name,mode和correction                        
    1028         .align  5   
    
    1030 vector_\name:                                                                   
    1031         .if \correction                                                         
    1032         sub     lr, lr, #\correction                                            
    1033         .endif                                                                  
    1034                                                                                 
    1035         @                                                                       
    1036         @ Save r0, lr_<exception> (parent PC) and spsr_<exception>              
    1037         @ (parent CPSR)                                                         
    1038         @                                                                       
    1039         stmia   sp, {r0, lr}            @ save r0, lr                           
    1040         mrs     lr, spsr                                                        
    1041         str     lr, [sp, #8]            @ save spsr                             
    1042                                                                                 
    1043         @                                                                       
    1044         @ Prepare for SVC32 mode.  IRQs remain disabled.                        
    1045         @                                                                       
    1046         mrs     r0, cpsr                                                        
    1047         eor     r0, r0, #(\mode ^ SVC_MODE | PSR_ISETSTATE)                     
    1048         msr     spsr_cxsf, r0                                                   
    1049                                                                                 
    1050         @                                                                       
    1051         @ the branch table must immediately follow this code                    
    1052         @                                                                       
    1053         and     lr, lr, #0x0f                                                   
    1054  THUMB( adr     r0, 1f                  )                                       
    1055  THUMB( ldr     lr, [r0, lr, lsl #2]    )                                       
    1056         mov     r0, sp                                                          
    1057  ARM(   ldr     lr, [pc, lr, lsl #2]    )                                       
    1058         movs    pc, lr                  @ branch to handler in SVC mode         
    1059 ENDPROC(vector_\name)
    

    vector_irq的定义如下:

    1080         vector_stub     irq, IRQ_MODE, 4                                        
    1081                                                                                 
    1082         .long   __irq_usr                       @  0  (USR_26 / USR_32)         
    1083         .long   __irq_invalid                   @  1  (FIQ_26 / FIQ_32)         
    1084         .long   __irq_invalid                   @  2  (IRQ_26 / IRQ_32)         
    1085         .long   __irq_svc                       @  3  (SVC_26 / SVC_32)         
    1086         .long   __irq_invalid                   @  4                            
    1087         .long   __irq_invalid                   @  5                            
    1088         .long   __irq_invalid                   @  6                            
    1089         .long   __irq_invalid                   @  7                            
    1090         .long   __irq_invalid                   @  8                            
    1091         .long   __irq_invalid                   @  9                            
    1092         .long   __irq_invalid                   @  a                            
    1093         .long   __irq_invalid                   @  b                            
    1094         .long   __irq_invalid                   @  c                            
    1095         .long   __irq_invalid                   @  d                            
    1096         .long   __irq_invalid                   @  e                            
    1097         .long   __irq_invalid                   @  f                            
    1098                                                       
    

    中断硬件准备

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

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

    1. 修改CPSR(Current Program Status Register)寄存器中的M[4:0]。改变CPSR中M[4:0],把模式切换成IRQ MODE模式。
      2)保存发生中断那一点的CPSR值(step 1之前的状态)和PC值。(比如在用户空间,就保存用户空间的CPSR和PC;在内核空间,就保存内核空间的CPSR和PC)
      2.1 中断那一刻的CPSR,保存到IRQ MODE的SPSR中
      2.3 中断那一一刻的PC,保存到LR_IRQ中
      对于thumb state,lr_irq = PC
      对于ARM state,lr_irq = PC - 4
      3、mask IRQ exception。也就是设定CPSR.I = 1
      4、设定PC值为IRQ exception vector。
      系统现在从发生中断之前的模式(比如用户或者内核模式)切换成IRQ模式。

    struct stack {
    u32 irq[3];
    u32 abt[3];
    u32 und[3];
    } ____cacheline_aligned;

    static struct stack stacks[NR_CPUS];

    4. vector_irq的处理流程

    跳转到vector_irq模式,这个模式下 lr_irq保存发生中断时刻的PC 指针,IRQ_SPSR保存发生中断时刻的CPSR。
    1)lr_irq= PC -4 (中断时刻PC寄存器) IRQ_SPSR= CPSR(中断时刻的CPSR)
    2)在cpu_init中SP_IRQ指向stacks->irq地址,通过stmia sp, {r0, lr} 指令,stacks->irq[0]=r0(中断前的r0),stacks->irq[1]=LR_IRQ=PC-8(中断时刻下一条要执行的命令),通过 mrs lr, spsr和str lr, [sp, #8],stacks->irq[2]=LR_SPSR=CPSR(中断时刻的CPSR)
    3)把SP_IRQ,存放到r0中。
    4)PC设置为根据发生中断时刻的状态的处理函数地址,并且把IRQ模式切换为SVC模式。

    1030 vector_\name:                                                                   
    1031         .if  4                                                         
    1032         sub     lr, lr, 4    //     /*计算返回地址(在arm流水线中,lr=pc+8,但是pc+4只译码没有执行,所以lr=lr-4) */                           
    1033         .endif                                                                  
    1034                                                                                 
    1035         @                                                                       
    1036         @ Save r0, lr_<exception> (parent PC) and spsr_<exception>              
    1037         @ (parent CPSR)                                                         
    1038         @                                                                       
    1039         stmia   sp, {r0, lr}            @ save r0, lr           //把r0和lr寄存器的内容保存到sp寄存器保存的地址中                
    1040         mrs     lr, spsr                                      //把状态寄存器spsr的内容保存到lr寄存器器中                  
    1041         str     lr, [sp, #8]            @ save spsr    
              //  将lr的内容保存到SP指向的地址加上8个字节后的地址中,就是栈指针SP+8保存的内容是spsr。
    1042                                                                                 
    1043         @                                                                       
    1044         @ Prepare for SVC32 mode.  IRQs remain disabled.                        
    1045         @                                                                       
    1046         mrs     r0, cpsr                            
           //将cpsr的寄存器的值保存到r0寄存器中                            
    1047         eor     r0, r0, #(\mode ^ SVC_MODE | PSR_ISETSTATE)          
         //mode=IRQ_MODE=0x00000012  SVC_MODE=0x13  PSR_ISETSTATE=0x20
         // #(\mode ^ SVC_MODE | PSR_ISETSTATE) =0x12^0x13|0x20=0x1|0x20=0x21
         //eor是异或,r0和0x21异或后,保存到r0中,就是反转bit0和bit5,也就是把CPSR寄存器中的bit0和bit5反转后,保存到r0寄存器中。
         
         
    1048         msr     spsr_cxsf, r0         
    //把r0寄存器中的内容给SPSR,也就是把寄存器CPSR的bit0和bit5反转后,保存到SPSR寄存器。
    //之前是THUMB模式转换为ARM模式,IRQ模式转换为SVC模式                                    
    1049                                                                                 
    1050         @                                                                       
    1051         @ the branch table must immediately follow this code                    
    1052         @                                                                       
    1053         and     lr, lr, #0x0f           
    //       把lr寄存器中的内容保留bit3-bit0。 就是把spsr的模式位保存下来      就是在进入中断模式前,CPSR就是进中断的模式存到CPSR中。 
    1054  THUMB( adr     r0, 1f                  )          //THUMB是在THUMB模式下才执行的命令                             
    1055  THUMB( ldr     lr, [r0, lr, lsl #2]    )                                 
    1056         mov     r0, sp                                //把sp占地保存到r0中。                              
    1057  ARM(   ldr     lr, [pc, lr, lsl #2]    )          /如果进入中断前是usr,则lr=0   如果是SVC,则lr=3                    
    1058         movs    pc, lr                  @ branch to handler in SVC mode     //此时已经切换成SVC模式    
    1059 ENDPROC(vector_\name)
    

    问题1:
    THUMB或者ARM宏在哪种模式下执行?

    THUMB宏在THUMB模式下执行。
    ARM宏在 ARM模式下执行。

    问题2:

    在这里插入图片描述

    1054  THUMB( adr     r0, 1f                  )          //THUMB是在THUMB模式下才执行的命令                             
    1055  THUMB( ldr     lr, [r0, lr, lsl #2]    )       
    

    如果lr=0,则ldr lr,[r0,lr,lsl #2]后,lr=r0+lr*4=r0,因为lr是标签1的地址,但是1:的 入口地址为什么是.long __irq_usr?
    因为1:和__irq_usr之间的代码不占空间。

    其他

    1.1 SWI异常

    在__vectors_start中W(ldr) pc, __vectors_start + 0x1000 ,指的软中断SWI。
    如下图中所示,在System.map中查看,可以看到 __vectors_start + 0x1000,也就是 __stubs_start。
    stubs_start
    查看__stubs_start的定义如下,可以看到__stubs_start指向vector_swi标签。

    1067 __stubs_start:                                                                  
    1068         @ This must be the first word                                           
    1069         .word   vector_swi 
    

    1.2 CPSR寄存器

    M[4:0]模式
    0b10000用户
    0b10001FIQ
    0b10010IRQ
    0b10011管理模式
    0b10111中止
    0b11011未定义
    0b11011系统
    bit5工作状态
    1Thumb
    0ARM

    注:
    所有处理器模式下都可访问当前程序状态寄存器CPSR。CPSR中包含条件码标志、中断禁止位、当前处理器模式以及其他状态和控制信息。在每种异常模式下都有一个对用的程序状态寄存器SPSR。当异常出现时,SPSR用于保存CPSR的状态,以便异常返回后恢复异常发生时的工作状态。

    c - control field mask byte(xPSR[7:0])
    x - extension field mask byte(xPSR[15:8])
    s - status field mask byte(xPSR[23:16)
    f - flags field mask byte(xPSR[31:24]).
    老式声明方式:cpsr_flg,cpsr_all在ADS中已经不在支持
    cpsr_flg对应cpsr_f
    cpsr_all对应cpsr_cxsf
    

    参考

    分析在linux中的中断是如何运行的,以及中断3大结构体:irq_desc、irq_chip、irqaction
    ARM中断表与响应流程
    Linux系统调用过程中user栈的保存与恢复
    linux中断中(异常向量详解)

    展开全文
  • 在32位ARM系统中,一般都是在中断向量表中放置一条分支指令或PC寄存器加载指令,实现程序跳转到中断服务例程的功能。
  • 中断向量重定位单片机中实现IAP和APP中断的方法.pdf
  • 基于 C 语言设置 TMS320 DSP 中断向量表 摘要 随着 DSP 芯片 应用 的不断深入用 C 语言开发 DSP 芯片不仅可以使 DSP 芯 片的开发速度大大提高也使得程序的修改和移植变得十分方便C 语言设置 TMS320 系 列 DSP 中断向...
  • 8086中断向量

    2022-04-10 15:46:23
    微机原理 | 8086中断向量

    通俗易懂,留着复习用

    8086共有2^8=256个不同的中断源,每一个中断源都有唯一的一个中断识别号,即中断类型码。

    每一个中断类型码对应着一个中断向量,本质上来说中断向量就是中断服务子程序的唯一确定的一个入口地址,这个地址由中断服务子程序的段地址CS和偏移地址IP组成,共占内存4B(CS、IP均为16位,分别占两个字节)。中断向量的入口地址按照中断类型码的顺序存放在一段连续排列的存储区域内,这个存储区域就称为中断向量表。

    8086的中断向量表占用了256*4=1KB的地址空间(00000H~003FFH),故8086的中断向量表位的起始地址为00000H,在微机系统初始化的时候,系统将中断源(0~255)的中断服务子程序的入口地址(即中断向量)按顺序填写在中断向量表中。

    其中,中断向量类型码为n的中断向量在表中的逻辑地址为0000:4n。这里需要补充一个知识点:

    逻辑地址=段地址:偏移地址

    物理地址=段地址*10H+偏移地址    (7018H*10H=70180H)

    逻辑地址中的4n即该中断向量在表中的存放地址(00000H~003FFH)。

    在某度看到了这张表,是我认为最直接最清晰的表了,如下:

     

    中断向量的存放方式:低地址的两字节存放中断服务子程序入口地址的偏移地址IP,高地址的两字节存放入口地址的段基址CS。

    IP、CS地址具体存放方式:高八位放高地址,低八位放低地址。(地址编号大的为高地址,反之低地址,如0000H~003FFH依次从低地址到高地址)

    再补充个知识点:高、低字节 &大小端模式

    大端、小端说明的是数据的组织方式。

    低字节放在高地址,高字节放在低地址称为大端模式,

    高字节放在高地址,低字节放在低地址称为小端模式。

    eg.一个十六进制的数FF1A,高字节是FF,低字节是1A。

    总结来说就是左边是高字节,右边是低字节

    8086系统的数据组织方式属于小端模式。

    来看个例题:

    8086中,中断类型码为 18H 的中断向量存放在内存中的 4 个字节单元中,其中的字节单元内容从低字节到高字节依次为 1AH、2BH、3CH、4DH, 则 18H 号中断服务程序入口地址是多少? 

    4D3C:2B1A

    展开全文
  • PIE支持的96个中断,每个中断都有自己的中断向量存放在RAM中,构成整个系统的中断向量表,如表所列,用户可以根据需要适当地对中断向量表进行调整。在响应中断时,CPU将自动地从中断向量表中获取相应的中断向量。CPU...
  • 在F281x DSP中采用外设中断扩展模块(Peripheral Interrupt Expansion,PIE)解决上述问题。外设中断扩展模块实质上是将中断向量表范围扩展...中断向量映射主要由以下位/信号来控制。  该位在状态寄存器1(ST1)的位
  • 51内核的最基础的中断源请求有外部中断、定时器中断和串口中断,这也是学习和开发者最长用的。当然还有其他的中断源,比如ADC、SPI、PWM等。以外部中断0为例,在编程中常使用的方式为:void INT0()interrupt 0 using...

    51内核的最基础的中断源请求有外部中断、定时器中断和串口中断,这也是学习和开发者最长用的。当然还有其他的中断源,比如ADC、SPI、PWM等。以外部中断0为例,在编程中常使用的方式为:

    void INT0()interrupt 0 using 1

    {

    ……

    }

    在这里特别做上笔记:其中前面的void INT0() 只是代表一个普通没有形参的函数而已,函数名写成什么都是可以的,这个到不重要。那么后面的就一个一个词的扣把:(2-1-i-c-中国-电子网,防抓取)

    其中 interrupt n 组成一组,n用来指明中断号,在函数后使用了interrupt关键字后,就会自动的生成中断向量,51内核中断号如下图,这是我今天查的正在使用的MCU:

    c73cae3f2694bd04ab69562ea472b16c.png

    例如:

    12

    interrupt 1 指明是定时器中断0;

    interrupt 2 指明是外部中断1;

    interrupt 3 指明是定时器中断1

    。。。

    对于51内核的MCU,不同厂家及不同型号的内部资源会有所不同,上图是我正在开发的一款中颖SH88F516单片机,由上图可见内部资源还算可以,能够满足一般的产品。后面的using n 指的是使用第n组寄存器。这个之前我在使用的过程中往往忽略了这个,也没有出现什么问题。但是今天注意到这个问题,查完资料后用上发现效果还不如不用,很有肯能是没有把这个知识用好的原因把。对比之后给我的感觉是在使用C语言写程序时,能不用就不用吧。查资料解释说假如在中断函数中使用了using n,中断不再保存R0-R7的值,这也就意味着假如一个高优先级的中断及一个低优先级的中断同时使用了using n,而这个n恰恰相等,那就等着哭把,因为这个BUG还真不是那么好找出来的(今天我就遇到了这个问题)。21ic整理

    其次就是中断优先级的问题了,如图上面的中断表,在右侧第二栏标的很清楚,除了复位之外,就数外部中断0优先级最高了,依次往下排列,那么问题来了,今天刚好就碰到了需要串口0的优先级比定时器0的优先级高。没办法,只好接着啃数据手册,还好这寄存器不多,一会就查到了下表和相关的描述:

    88d5cf0f83b45916893ac7e06024e9ab.png

    所以按照描述修改下优先级就可以达到目的了。

    总结:用到回过头来用到51的中断,发现有些东西在之前学习的时候并没有太在意,导致现在在开发产品上使用的时候不清楚用途。因为工作跟学习性质是不一样的,作为开发者的角度来说,质量往往是第一要求。同时会接触到很多新鲜的事物和技术,但是话又说回来了,最基本的知识还是需要打牢。

    展开全文
  • 问:What is interrupt? 百度百科:中断是指在计算机执行程序的过程中,...在某些计算机中,中断向量的位置存放一条跳转到中断服务程序入口地址的跳转指令。 中断向量地址:内存中存放中断服务程序入口地址的地址 ...
  • 因为中断向量重定位是在main函数中完成的,重定位中断向量之前的中断向量依然执行BootLoader中的中断向量表,main函数中完成中断向量重定位后如果再发生中断,那么就执行重定位后的中断向量表 ...
  • AD测试程序中断向量代码  欢迎转载,信息来源维库电子市场网(www.dzsc.com) 来源:ks99
  • 什么是中断向量?中断向量表的地址范围? 答:中断就是CPU在执行当前程序时由于内外部事件引起CPU暂时停止当前正在执行的程序而转向执行请求CPU暂时停止的内外部事件的服务程序,该程序处理完后又返回继续执行被停止...
  • 中断向量,中断向量表 ,中断服务函数

    千次阅读 多人点赞 2019-07-29 12:31:52
    所谓中断是指CPU在正常执行程序的过程中,由于内部/外部事件的触发或由程序的预先安排,引起CPU暂时...中断向量:中断的地址的变量; 中断向量表:中断类型号与相应中断源的中断处理程序入口地址之间的连接表; ...
  • keil 51 使用C语言中断向量keil 51 使用C语言中断向量中断源的矢量位置中断源 Keil中断编号 矢量地址最高优先级 6 0x0033外部中断0 0 0x0003定时器0溢出 1 ...
  • 中断向量与向量地址 中断号——中段的编号 什么是中断向量?我们可以把它理解成中断服务程序的入口地址。 比如说在 x86 系列当中,我们可以把中断向量理解成中断服务程序的段地址和偏移量组成的一个向量。 有的时候...
  • 在IAR环境下用户程序的地址及中断向量设置,在IAR环境下用户程序的地址及中断向量设置
  • STM32(Cortex-M3)中有两个优先级的概念——抢占式优先级和响应优先级,有人把响应优先级称作'亚优先级'或'副优先级',每个中断源都需要被指定这两种优先级。
  • 中断向量为:编程将中断向量类型21H所对应的中断向量从中断向量表中取出来分别放在 SI 和 BP中。(直接用 MOV 指令即可) CODE SEGMENT ASSUME CS:CODE START: XOR AX,AX ;AX清空 MOV DS,AX ;DS不可直接 MOV 立即...
  • 中断类型号为32H的中断向量存放在内存哪里(指明段地址和偏移地址的范围)?如果32H的中断处理子程序从13A4H:25B0H开始,中断向量应怎样存放(指明该中断的中断向量表中每个字节保存的内容)? 32H*4=0C8H, 中断...
  • 功能:程序终止产生中断,所以我们可以写一个内存有问题的子程序,调用它就会产生一个 0H 中断 例如:200H / 0H 等于无穷,导致程序内存溢出终止,产生 0H 号中断 key_I: MOV AX,200H ;程序错误中断0(200H / 0...
  • 计算机组成:中断向量的相关计算

    千次阅读 2019-05-25 16:19:36
    中断向量的相关计算 中断码 0~255一个256个中断码,一个中断码占4字节。 1号中断向量:00000H~00003H。比如中断码15H,那么起始的地址:15H × 4 = 00054H(可以转换成10进制计算。注意题目要求的格式是否要前面...
  • IC基础知识(十)中断向量地址

    千次阅读 2020-12-24 09:15:42
    中断向量地址
  • STM32中断向量偏移

    千次阅读 2019-01-25 11:26:22
    总结一下在IAP升级中APP程序的中断向量表的偏移 1. 关于APP程序的中断向量表地址偏移(三种方法,stm32F2与F4系列通用。三种方法本质一样只是看到网上的各种例程的表现形式不一样) ① 直接操作寄存器 在APP程序的...
  • 2:中断矢量发生器(TAIV, Interrupt Vector Generator): TACCR1 CCIFG、TACCR2 CCIFG和TAIFG标志被按优先级排序并组合为单个中断向量的来源。 中断向量寄存器TAIV用于确定哪个标志请求中断。 最高优先级使能的中断...
  • 原文地址 在做stm32 iap升级固件的时候通常需要多份中断向量表。比如bootloader的中断向量表在0x00000000位置,应用程序的中断向...VTOR是arm内核的一个寄存器,叫做中断向量偏移量寄存器。当系统上电启动的时候CPU...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 43,177
精华内容 17,270
关键字:

中断向量

友情链接: UART_TX.zip