免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
最近访问板块 发新帖
查看: 5111 | 回复: 0
打印 上一主题 下一主题

[FreeBSD] freebsd9.2-处理器间中断-发送 [复制链接]

论坛徽章:
0
跳转到指定楼层
1 [收藏(0)] [报告]
发表于 2014-07-06 01:05 |只看该作者 |倒序浏览
有了前面"内核如何实现IA32中断处理"中的内容作为准备,依然将处理器间中断简称为IPI,下面结合ULE线程调度来看一下IPI的发送过程。

先来看一下需要用到的数据结构:

[数组cpu_ipi_pending]-用来处理IPI_AST,IPI_PREEMPT,IPI_HARDCLOCK三个特殊的IPI:
  1. /*****************************************************************************
  2. * Holds pending bitmap based IPIs per CPU 。
  3.    
  4.    数组cpu_ipi_pending和下面的IPI中断向量号结合起来理解会更清楚:

  5.    #define        IPI_BITMAP_VECTOR        249

  6.    对于下面三个IPI的描述为"IPIs handled by IPI_BITMAPED_VECTOR":
  7.    #define IPI_AST                0        
  8.    #define IPI_PREEMPT          1
  9.    #define IPI_HARDCLOCK        2

  10.    IPI_AST:忽略,内核中的描述"Nothing to do for AST"。

  11.    IPI_PREEMPT:需要抢占时发送。
  12.    
  13.    IPI_HARDCLOCK:
  14.    在SMP系统中,只有BSP上的APIC TIMER启用,而其余AP上的APIC TIMER没有启用
  15.    时,当BSP上的APIC TIMER超时后,就会向其余AP发送一个IPI_HARDCLOCK
  16.    类型的IPI。
  17.   
  18.    由此看见,当发送类型为IPI_AST,IPI_PREEMPT,IPI_HARDCLOCK的IPI时,
  19.    其实是通过中断向量号为IPI_BITMAP_VECTOR对应的中断处理程序来处理的,
  20.    那么就需要通过一种方法,该方法能够设置一个标志,中断向量号为
  21.    IPI_BITMAP_VECTOR对应的中断处理程序通过检查相应的标志来确定发送的
  22.    是IPI_AST,IPI_PREEMPT,IPI_HARDCLOCK三个IPI的哪一个,这个这个方法
  23.    就是使用数组cpu_ipi_pending。

  24.    系统中每个cpu在数组cpu_ipi_pending中都有相应的元素,logical cpu id
  25.    作为数组cpu_ipi_pending的索引。

  26.    假设系统中某个cpu的logical cpu id为1,那么当该cpu接收到一个
  27.    中断向量号为IPI_BITMAP_VECTOR的中断时,相应的中断处理程序就会检查
  28.    数组元素cpu_ipi_pending[1]中IPI_AST,IPI_PREEMPT,IPI_HARDCLOCK对应
  29.    的bit位是否被设置为1,如果是,就进行相应的处理。设置为1的任务由
  30.    发送IPI的cpu来完成。

  31.    通过上面的描述,可以看出,数组cpu_ipi_pending用来描述系统中某个cpu
  32.    是否有挂起的IPI_AST,IPI_PREEMPT,IPI_HARDCLOCK的IPI。
  33. ********************************************/
  34.    198  static volatile u_int cpu_ipi_pending[MAXCPU];
复制代码
[和IPI计数器相关的数组]-对cpu上接收到的IPI进行计数:
  1. /*******************************************************************************
  2. * 只有在编译内核时选择了COUNT_IPIS选项,下面的描述才有效。

  3.    161-169:
  4.    下面的数组对IPI进行计数,每个数组都对应一个IPI类型。
  5.    对于某一个特定数组,这里假设为数组数组ipi_invltlb_counts,系统中每个cpu
  6.    都在ipi_invltlb_counts数组中有相应的元素,数组的索引为logical cpu id。

  7.    对于cpu0,当cpu0接收到一个类型为IPI_INVLTLB的IPI时,相应的中断处理程序
  8.    就会递增*ipi_invltlb_counts[0].


  9.    u_long intrcnt[INTRCNT_COUNT];
  10.    char intrnames[INTRCNT_COUNT * (MAXCOMLEN + 1)];
  11.    
  12.    初始化函数mp_ipi_intrcnt完成两个主要任务:
  13.    1:用intrcnt数组元素的地址初始化下面的指针数组。
  14.    2:使用类似"cpu%d:invltlb"这样的字符串初始化上面的intrname数组,这里的%d
  15.       为cpu的logical cpu id。
  16. *********************************************/
  17.    161  static u_long *ipi_preempt_counts[MAXCPU];
  18.    162  static u_long *ipi_ast_counts[MAXCPU];
  19.    163  u_long *ipi_invltlb_counts[MAXCPU];
  20.    164  u_long *ipi_invlrng_counts[MAXCPU];
  21.    165  u_long *ipi_invlpg_counts[MAXCPU];
  22.    166  u_long *ipi_invlcache_counts[MAXCPU];
  23.    167  u_long *ipi_rendezvous_counts[MAXCPU];
  24.    168  u_long *ipi_lazypmap_counts[MAXCPU];
  25.    169  static u_long *ipi_hardclock_counts[MAXCPU];
复制代码
[数组cpu_apic_ids和apic_cpuids]:
  1. /******************************************************************************************
  2. * #define        MAX_APIC_ID        0xfe
  3.    #define MAXCPU                32

  4.    下面两个数组都是由函数assign_cpu_ids初始化的,该函数在初始化函数cpu_mp_start中被调用。

  5.    数组cpu_apic_ids的索引为logical cpu id,相应数组元素的值为cpu的local APIC ID。
  6.    数组apic_cpuids的索引为cpu的local APIC ID,相应数组元素的值为cpu的logical cpu id。  
  7. ********************************************/
  8.    194        int cpu_apic_ids[MAXCPU];
  9.    195        int apic_cpuids[MAX_APIC_ID + 1];
复制代码
[struct tdq对象中的tdq_ipipending成员]:
  1. /******************************************************************************
  2. * tdq - per processor runqs and statistics.  All fields are protected by the
  3. * tdq_lock.  The load and lowpri may be accessed without to avoid excess
  4. * locking in sched_pickcpu();
  5.    对于SMP系统:
  6.    每个cpu对应的一个struct tdq数据对象,数组tdq_cpu以cpu的logical id为索引。
  7.    static struct tdq       tdq_cpu[MAXCPU];

  8.    对于非SMP系统:
  9.    系统中只定义了一个struct tdq数据对象。
  10.    static struct tdq       tdq_cpu;

  11.    tdq_ipipending:表示是否有挂起的IPI。
  12. *****************************************************/
  13.    225  struct tdq {
  14. 。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。
  15.    236          u_char          tdq_ipipending;         /* IPI pending. */
  16. 。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。
  17.    246  } __aligned(64);
复制代码
根据之前sched_add函数的描述,当把一个线程td添加到系统中某个cpu(假设为cpu5)的运行队列时,就会检查td是否能够抢占当前
正在cpu5上运行的线程,如果可以抢占,就要给cpu5发送一个IPI。
[摘取sched_add函数的部分代码]:
  1. /**************************************************************************************
  2. * Select the target thread queue and add a thread to it.  Request
  3. * preemption or IPI a remote processor if required.

  4.    参数描述:

  5.    td:标识将要被添加到cpu运行队列中的线程。

  6.    flags:传递给函数sched_add的标志,相关标志需要结合上下文分析,这里暂且略过。
  7. **************************************/
  8.   2342        
  9.   2343        void
  10.   2344        sched_add(struct thread *td, int flags)
  11.   2345        {
  12. 。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。
  13. /***************************************************************************************
  14. * 2365-2377:SMP系统
  15. *
  16. * Pick the destination cpu and if it isn't ours transfer to the
  17. * target cpu.

  18.    2370:函数sched_pickcpu为线程td挑选一个合适的cpu,局部变量smp_cpu保存了该
  19.          cpu的logical cpu id,这里假设为5。

  20.    2371:函数sched_setcpu主要完成下面的工作:
  21.          将和线程td相关联的struct td_sched数据对象的ts_cpu成员设置为smp_cpu。
  22.          并返回logical cpu id为smp_cpu的运行队列,这里假设为&tdq_cpu[5]。
  23. ***********************************/
  24.   2365        #ifdef SMP
  25. 。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。
  26.   2370                smp_cpu = sched_pickcpu(td, flags);
  27.   2371                tdq = sched_setcpu(td, smp_cpu, flags);
  28. /************************************************************************
  29. * 2373-2376:
  30.    如果smp_cpu和当前cpu的logical cpu id不相等,那么就调用函数
  31.    tdq_notify检查线程td是否能够抢占当前正在cpu logical id为smp_cpu
  32.    上运行的线程,如果可以,就发送一个IPI。
  33. *********************************************************/
  34.   2373                if (smp_cpu != PCPU_GET(cpuid)) {
  35.   2374                        tdq_notify(tdq, td);
  36.   2375                        return;
  37.   2376                }
  38. 。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。
  39.   2389        }
复制代码
[摘取函数tdq_notify的部分代码]:
  1. /*******************************************************************************
  2. * Notify a remote cpu of new work.  Sends an IPI if criteria are met.
  3.    对于logical cpu id为5的cpu,此时参数描述及相应成员的取值如下:

  4.    参数描述:

  5.    tdq:为&tdq_cpu[5]。

  6.    td:已经被添加到运行队列tdq_cpu[5]的tdq_realtime队列,tdq_timeshare队列,

  7.        tdq_idle队列三个队列之一中的线程。

  8.    成员取值描述:
  9.    td->td_sched->ts_cpu的值为5。
  10. ***************************************************************************/           
  11.   1011        static void
  12.   1012        tdq_notify(struct tdq *tdq, struct thread *td)
  13.   1013        {
  14. 。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。
  15. /************************************************************
  16. * 1018-1019:
  17.    如果struct tdq对象的tdq_ipipending成员非零,表示此时正在
  18.    发送IPI,此时直接返回。
  19. *****************************************/
  20.   1018                if (tdq->tdq_ipipending)
  21.   1019                        return;
  22. 。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。
  23. /***************************************************************
  24. * 如果执行到这里,就表示线程td将抢占线程ctd。
  25. * 1033:将struct tdq对象的tdq_ipipending成员设置为1。

  26.    1034:发送类型为IPI_PREEMPT的IPI。

  27.    变量cpu的值为5。
  28. ********************************************************/
  29.   1033                tdq->tdq_ipipending = 1;
  30.   1034                ipi_cpu(cpu, IPI_PREEMPT)
  31.   1035        }
复制代码
从上面的描述中可以看出,调用函数ipi_cpu来发送一个IPI,函数ipi_cpu是内核提供的用来发送IPI的接口。

[函数ipi_cpu]:
  1. /************************************************************************
  2. * send an IPI to a specific CPU.
  3.    参数描述:

  4.    cpu:接收IPI的cpu的logical cpu id,这里假设为5。

  5.    ipi:
  6.    一般情况下为中断向量号。
  7.    当发送IPI_AST,IPI_PREEMPT,IPI_HARDCLOCK三个特殊的IPI时,对应
  8.    的不是中断向量号。

  9.    这里ipi的值为IPI_PREEMPT。

  10.    该函数实际上是函数ipi_send_cpu的一个简单封装。
  11. ********************************************/
  12.   1419        void
  13.   1420        ipi_cpu(int cpu, u_int ipi)
  14.   1421        {
  15.   1422       
  16. /***********************************************************************
  17. * IPI_STOP_HARD maps to a NMI and the trap handler needs a bit
  18. * of help in order to understand what is the source.
  19. * Set the mask of receiving CPUs for this purpose.

  20.    1428-1429:
  21.    #define        IPI_STOP_HARD        252    Stop CPU with a NMI.
  22.    忽略之间的处理。  

  23.    1432:ipi_send_cpu函数见下面的描述。                 
  24. *******************************/
  25.   1428                if (ipi == IPI_STOP_HARD)
  26.   1429                        CPU_SET_ATOMIC(cpu, &ipi_nmi_pending);
  27.   1430       
  28.   1431                CTR3(KTR_SMP, "%s: cpu: %d ipi: %x", __func__, cpu, ipi);
  29.   1432                ipi_send_cpu(cpu, ipi);
  30.   1433        }
复制代码
[函数ipi_send_cpu]:
  1. /***************************************************************************************
  2. * Send an IPI to specified CPU handling the bitmap logic.
  3. * 参数描述:

  4.    cpu:接收IPI的cpu的logical cpu id,这里假设为5。   

  5.    ipi:
  6.    一般情况下为中断向量号。
  7.    当发送IPI_AST,IPI_PREEMPT,IPI_HARDCLOCK三个IPI时,对应
  8.    的不是中断向量号。

  9.    这里ipi的值为IPI_PREEMPT。

  10.    函数ipi_send_cpu的任务就是针对IPI_AST,IPI_PREEMPT,IPI_HARDCLOCK三个特殊的IPI
  11.    做相应的处理。
  12. ***********************************
  13.   1190        static void
  14.   1191        ipi_send_cpu(int cpu, u_int ipi)
  15.   1192        {
  16.   1193                u_int bitmap, old_pending, new_pending;
  17.   1194       
  18.   1195                KASSERT(cpu_apic_ids[cpu] != -1, ("IPI to non-existent CPU %d", cpu));
  19. /***********************************************************************************************************
  20. * 1197-1207:
  21.    如果发送的是IPI_AST,IPI_PREEMPT,IPI_HARDCLOCK三个特殊的IPI就进行相应的处理。
  22.    
  23.    #define        IPI_AST                0        
  24.    #define      IPI_PREEMPT     1
  25.    #define      IPI_HARDCLOCK   2
  26.    #define IPI_BITMAP_LAST IPI_HARDCLOCK  2
  27.    #define IPI_IS_BITMAPED(x) ((x) <= IPI_BITMAP_LAST)
  28.    
  29.    1197:
  30.    宏IPI_IS_BITMAPED检查ipi是否为IPI_AST或者IPI_PREEMPT或者IPI_HARDCLOCK,如果是,宏的值就为真。
  31.    这里为IPI_IS_BITMAPED(IPI_PREEMPT)   IPI_PREEMPT <= IPI_BITMAP_LAST,很明显为真。

  32.    1198:变量bitmap为二进制10。

  33.    1199:此时重新设置变量ipi,将其设置为IPI_BITMAP_VECTOR,即中断向量号249。

  34.    由此可以看出,当发送IPI_AST,IPI_PREEMPT,IPI_HARDCLOCK三个特殊的IPI时,实际上发送的IPI的中断向量号
  35.    都为IPI_BITMAP_VECTOR。

  36.    1200-1203,do-while循环:
  37.    1201:old_pending保存的是当前数组元素cpu_ipi_pending[5]的值。
  38.    1202:new_pending为将要赋值给数组元素cpu_ipi_pending[5]的新值。

  39.    do_while循环一直执行,直到old_pending和cpu_ipi_pending[cpu]的值相等时为止,此时函数atomic_cmpset_int
  40.    返回1,数组元素cpu_ipi_pending[cpu]的值被更新为new_pending。
  41.   
  42.    因为APIC同时允许有两个挂起的相同中断,freebsd9.2貌似为了预防死锁,一次只允许有一个挂起的中断。

  43.    1205:如果old_pending非空,表示已经发送了一个中断向量号为IPI_BITMAP_VECTOR的IPI,但是cpu5还没有处理。
  44.          此时直接返回。
  45. *************************************************/
  46.   1197                if (IPI_IS_BITMAPED(ipi)) {
  47.   1198                        bitmap = 1 << ipi;
  48.   1199                        ipi = IPI_BITMAP_VECTOR;
  49.   1200                        do {
  50.   1201                                old_pending = cpu_ipi_pending[cpu];
  51.   1202                                new_pending = old_pending | bitmap;
  52.   1203                        } while  (!atomic_cmpset_int(&cpu_ipi_pending[cpu],
  53.   1204                            old_pending, new_pending));       
  54.   1205                        if (old_pending)
  55.   1206                                return;
  56.   1207                }
  57. /**************************************************************
  58. * 1208:
  59.    logical cpu id是内核用来标识cpu的,但是发送IPI时,必须使用
  60.    指定cpu的local APIC ID,这里就要用到数组cpu_apic_ids。

  61.    数组元素cpu_apic_ids[5]的值为cpu5的local APIC ID。
  62.    
  63.    此时,变量ipi已经被正确设置,调用函数lapic_ipi_vectored
  64.    发送IPI。
  65. *************************************/
  66.   1208                lapic_ipi_vectored(ipi, cpu_apic_ids[cpu]);
  67.   1209        }
复制代码
[函数lapic_ipi_vectored]-该函数构造将要写入到ICR中的值,下面再看看ICR的格式,假设其为0,一般情况下,Reserved
字段的值先读出,然后保证写入原值即可,这里假设Reserved字段的值为0:
  1. /***************************************************************************
  2. * 参数描述:
  3.    vector:中断向量号,这里为IPI_BITMAP_VECTOR,即中断向量号249。
  4.    dest:cpu5的local APIC ID,这里假设为X,X为local APIC ID的二进制表示。
  5. *****************************
  6.   1441        void
  7.   1442        lapic_ipi_vectored(u_int vector, int dest)
  8.   1443        {
  9. /**********************************************************************
  10. * icrlo:将要写入ICR低32位的值。
  11.    destfield:将要写入ICR高32位中Destination Field字段的值。

  12.    1449-1459:执行完后,icrlo的值为0x000000F9。
  13. *******************************/
  14.   1444                register_t icrlo, destfield;
  15.   1445       
  16.   1446                KASSERT((vector & ~APIC_VECTOR_MASK) == 0,
  17.   1447                    ("%s: invalid vector %d", __func__, vector));
  18.   1448       
  19.   1449                icrlo = APIC_DESTMODE_PHY | APIC_TRIGMOD_EDGE;
  20.   1450       
  21.   1451                /*
  22.   1452                 * IPI_STOP_HARD is just a "fake" vector used to send a NMI.
  23.   1453                 * Use special rules regard NMI if passed, otherwise specify
  24.   1454                 * the vector.
  25.   1455                 */
  26.   1456                if (vector == IPI_STOP_HARD)
  27.   1457                        icrlo |= APIC_DELMODE_NMI | APIC_LEVEL_ASSERT;
  28.   1458                else
  29.   1459                        icrlo |= vector | APIC_DELMODE_FIXED | APIC_LEVEL_DEASSERT;
  30. /******************************************************************************************
  31. * 因为这里是发送给指定cpu的IPI,所以dest为目的cpu的local APIC ID。

  32.    1462-1464:IPI的目的地为仅包括发送此IPI的cpu,此时icrlo的值为0x000400F9。
  33.    1465-1467:IPI的目的地为系统中全部cpu,包括发送此IPI的cpu,此时icrlo的值为0x000800F9。
  34.    1468-1470:IPI的目的地为系统中除发送此IPI的cpu以外的cpu,此时icrlo的值为0x000C00F9。
  35.      
  36.    如果switch语句从上面任意三个case中的一个跳出,destfield的值不变,即为0。

  37.    针对这里讨论的情况,destfield的值为X,icrlo的值为0x000000F9。   
  38. ************************************/
  39.   1460                destfield = 0;
  40.   1461                switch (dest) {
  41.   1462                case APIC_IPI_DEST_SELF:
  42.   1463                        icrlo |= APIC_DEST_SELF;
  43.   1464                        break;
  44.   1465                case APIC_IPI_DEST_ALL:
  45.   1466                        icrlo |= APIC_DEST_ALLISELF;
  46.   1467                        break;
  47.   1468                case APIC_IPI_DEST_OTHERS:
  48.   1469                        icrlo |= APIC_DEST_ALLESELF;
  49.   1470                        break;
  50.   1471                default:
  51.   1472                        KASSERT((dest & ~(APIC_ID_MASK >> APIC_ID_SHIFT)) == 0,
  52.   1473                            ("%s: invalid destination 0x%x", __func__, dest));
  53.   1474                        destfield = dest;
  54.   1475                }
  55.   1476       
  56. /*****************************************************************************************************
  57. * Wait for an earlier IPI to finish,检查是否有更早的IPI没有完成发送。
  58.    #define        BEFORE_SPIN        1000000
  59.    
  60.    ICR的字段Delivery Status:指示IPI的发送状态。0:IPI已经成功发送出去;1:还没有完成IPI的发送。

  61.    函数lapic_ipi_wait执行一个for循环,不停的测试Delivery Status字段的值,如果在指定的时间内,该
  62.    字段的值变为0,就返回1;否则返回0,表示出现了某种问题。

  63.    这个指定的时间为BEFORE_SPIN * (指令pause的时钟周期数)。
  64. *******************************************/
  65.   1478                if (!lapic_ipi_wait(BEFORE_SPIN)) {
  66.   1479                        if (panicstr != NULL)
  67.   1480                                return;
  68.   1481                        else
  69.   1482                                panic("APIC: Previous IPI is stuck");
  70.   1483                }
  71. /*****************************************************************************************************
  72. * 1485:
  73.    函数lapic_ipi_raw完成IPI的发送,见下面的描述。
  74. ***********************/
  75.   1485                lapic_ipi_raw(icrlo, destfield);
  76. /*************************************************************************
  77. * 执行到这里的话,IPI的发送已经完成。
  78. *
  79. * 1487-1512之间的代码只有在定义了DETECT_DEADLOCK才有意义,在有意义的
  80.    情况下,就是检查一下此次发送的IPI是否完成发送。
  81. ***************************************/
  82.   1487        #ifdef DETECT_DEADLOCK
  83.   1488                /* Wait for IPI to be delivered. */ #define        AFTER_SPIN        1000
  84.   1489                if (!lapic_ipi_wait(AFTER_SPIN)) {
  85.   1490        #ifdef needsattention
  86.   1491                        /*
  87.   1492                         * XXX FIXME:
  88.   1493                         *
  89.   1494                         * The above function waits for the message to actually be
  90.   1495                         * delivered.  It breaks out after an arbitrary timeout
  91.   1496                         * since the message should eventually be delivered (at
  92.   1497                         * least in theory) and that if it wasn't we would catch
  93.   1498                         * the failure with the check above when the next IPI is
  94.   1499                         * sent.
  95.   1500                         *
  96.   1501                         * We could skip this wait entirely, EXCEPT it probably
  97.   1502                         * protects us from other routines that assume that the
  98.   1503                         * message was delivered and acted upon when this function
  99.   1504                         * returns.
  100.   1505                         */
  101.   1506                        printf("APIC: IPI might be stuck\n");
  102.   1507        #else /* !needsattention */
  103.   1508                        /* Wait until mesage is sent without a timeout. */
  104.   1509                        while (lapic->icr_lo & APIC_DELSTAT_PEND)
  105.   1510                                ia32_pause();
  106.   1511        #endif /* needsattention */
  107.   1512                }
  108.   1513        #endif /* DETECT_DEADLOCK */
  109.   1514        }
复制代码
[函数lapic_ipi_raw]:
  1. /************************************************************************************
  2. * 参数描述:
  3.   
  4.    icrlo:将要写到ICR低32位的值,针对这里讨论的情况,值为0x000000F9。
  5.    
  6.    dest:目的cpu的local APIC ID或者为0,针对这里讨论的情况,值为X。
  7. *************************/
  8.   1407        void
  9.   1408        lapic_ipi_raw(register_t icrlo, u_int dest)
  10.   1409        {
  11.   1410                register_t value, saveintr;
  12.   1411       
  13.   1412                /* XXX: Need more sanity checking of icrlo? */
  14.   1413                KASSERT(lapic != NULL, ("%s called too early", __func__));
  15.   1414                KASSERT((dest & ~(APIC_ID_MASK >> APIC_ID_SHIFT)) == 0,
  16.   1415                    ("%s: invalid dest field", __func__));
  17.   1416                KASSERT((icrlo & APIC_ICRLO_RESV_MASK) == 0,
  18.   1417                    ("%s: reserved bits set in ICR LO register", __func__));
  19.   1418       
  20. /***********************************************************************************
  21. * Set destination in ICR HI register if it is being used.

  22.    1420:函数intr_disable将当前EFLAGS寄存器的值保存到变量中saveintr,之后清
  23.          EFLAGS寄存器的IF标志,表示此时禁止中断。
  24.    
  25.    针对这里讨论的情况,将执行1421-1426之间的语句。

  26.    变量lapic请参考"内核如何实现IA32中断处理"中的描述。

  27.    通过变量lapic访问cpu5的local APIC寄存器组:
  28.    lapic->icr_hi:访问ICR高32位。
  29.    
  30.    1422-1425:ICR高32位中的bit24-31被设置为X,bit0-23保持原来的值。
  31.      
  32.    执行完后ICR中Destination Field字段的值为X,即这个IPI将发送给cpu5。
  33. ******************************************/
  34.   1420                saveintr = intr_disable();
  35.   1421                if ((icrlo & APIC_DEST_MASK) == APIC_DEST_DESTFLD) {
  36.   1422                        value = lapic->icr_hi;
  37.   1423                        value &= ~APIC_ID_MASK;
  38.   1424                        value |= dest << APIC_ID_SHIFT;
  39.   1425                        lapic->icr_hi = value;
  40.   1426                }
  41. /******************************************************************************************
  42. * 通过变量lapic访问cpu5的local APIC寄存器组:
  43.    lapic->icr_lo:访问ICR低32位。

  44.    1429-1431:执行完后,value的值为0x000000F9。

  45.    1432:这个赋值操作就相当于对ICR低32位执行了一个写操作,ICR的Vector字段的值为0xF9。
  46.          
  47.    此时,已经向cpu5发出了一个IPI,该IPI的中断向量号为IPI_BITMAP_VECTOR,当cpu5
  48.    接收到这个中断时,就按照"内核如何实现IA32中断处理"中最后描述的中断处理机制进行处理。     

  49.    1432:用saveintr恢复EFLAGS寄存器。
  50. ****************************************/          
  51.   1428                /* Program the contents of the IPI and dispatch it. */
  52.   1429                value = lapic->icr_lo;
  53.   1430                value &= APIC_ICRLO_RESV_MASK;
  54.   1431                value |= icrlo;
  55.   1432                lapic->icr_lo = value;
  56.   1433                intr_restore(saveintr);
  57.   1434        }
复制代码
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

北京盛拓优讯信息技术有限公司. 版权所有 京ICP备16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年举报专区
中国互联网协会会员  联系我们:huangweiwei@itpub.net
感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

清除 Cookies - ChinaUnix - Archiver - WAP - TOP