- 論壇徽章:
- 0
|
有了前面"內(nèi)核如何實現(xiàn)IA32中斷處理"中的內(nèi)容作為準(zhǔn)備,依然將處理器間中斷簡稱為IPI,下面結(jié)合ULE線程調(diào)度來看一下IPI的發(fā)送過程。
先來看一下需要用到的數(shù)據(jù)結(jié)構(gòu):
[數(shù)組cpu_ipi_pending]-用來處理IPI_AST,IPI_PREEMPT,IPI_HARDCLOCK三個特殊的IPI:- /*****************************************************************************
- * Holds pending bitmap based IPIs per CPU 。
-
- 數(shù)組cpu_ipi_pending和下面的IPI中斷向量號結(jié)合起來理解會更清楚:
- #define IPI_BITMAP_VECTOR 249
- 對于下面三個IPI的描述為"IPIs handled by IPI_BITMAPED_VECTOR":
- #define IPI_AST 0
- #define IPI_PREEMPT 1
- #define IPI_HARDCLOCK 2
- IPI_AST:忽略,內(nèi)核中的描述"Nothing to do for AST"。
- IPI_PREEMPT:需要搶占時發(fā)送。
-
- IPI_HARDCLOCK:
- 在SMP系統(tǒng)中,只有BSP上的APIC TIMER啟用,而其余AP上的APIC TIMER沒有啟用
- 時,當(dāng)BSP上的APIC TIMER超時后,就會向其余AP發(fā)送一個IPI_HARDCLOCK
- 類型的IPI。
-
- 由此看見,當(dāng)發(fā)送類型為IPI_AST,IPI_PREEMPT,IPI_HARDCLOCK的IPI時,
- 其實是通過中斷向量號為IPI_BITMAP_VECTOR對應(yīng)的中斷處理程序來處理的,
- 那么就需要通過一種方法,該方法能夠設(shè)置一個標(biāo)志,中斷向量號為
- IPI_BITMAP_VECTOR對應(yīng)的中斷處理程序通過檢查相應(yīng)的標(biāo)志來確定發(fā)送的
- 是IPI_AST,IPI_PREEMPT,IPI_HARDCLOCK三個IPI的哪一個,這個這個方法
- 就是使用數(shù)組cpu_ipi_pending。
- 系統(tǒng)中每個cpu在數(shù)組cpu_ipi_pending中都有相應(yīng)的元素,logical cpu id
- 作為數(shù)組cpu_ipi_pending的索引。
- 假設(shè)系統(tǒng)中某個cpu的logical cpu id為1,那么當(dāng)該cpu接收到一個
- 中斷向量號為IPI_BITMAP_VECTOR的中斷時,相應(yīng)的中斷處理程序就會檢查
- 數(shù)組元素cpu_ipi_pending[1]中IPI_AST,IPI_PREEMPT,IPI_HARDCLOCK對應(yīng)
- 的bit位是否被設(shè)置為1,如果是,就進行相應(yīng)的處理。設(shè)置為1的任務(wù)由
- 發(fā)送IPI的cpu來完成。
- 通過上面的描述,可以看出,數(shù)組cpu_ipi_pending用來描述系統(tǒng)中某個cpu
- 是否有掛起的IPI_AST,IPI_PREEMPT,IPI_HARDCLOCK的IPI。
- ********************************************/
- 198 static volatile u_int cpu_ipi_pending[MAXCPU];
復(fù)制代碼 [和IPI計數(shù)器相關(guān)的數(shù)組]-對cpu上接收到的IPI進行計數(shù):- /*******************************************************************************
- * 只有在編譯內(nèi)核時選擇了COUNT_IPIS選項,下面的描述才有效。
- 161-169:
- 下面的數(shù)組對IPI進行計數(shù),每個數(shù)組都對應(yīng)一個IPI類型。
- 對于某一個特定數(shù)組,這里假設(shè)為數(shù)組數(shù)組ipi_invltlb_counts,系統(tǒng)中每個cpu
- 都在ipi_invltlb_counts數(shù)組中有相應(yīng)的元素,數(shù)組的索引為logical cpu id。
- 對于cpu0,當(dāng)cpu0接收到一個類型為IPI_INVLTLB的IPI時,相應(yīng)的中斷處理程序
- 就會遞增*ipi_invltlb_counts[0].
- u_long intrcnt[INTRCNT_COUNT];
- char intrnames[INTRCNT_COUNT * (MAXCOMLEN + 1)];
-
- 初始化函數(shù)mp_ipi_intrcnt完成兩個主要任務(wù):
- 1:用intrcnt數(shù)組元素的地址初始化下面的指針數(shù)組。
- 2:使用類似"cpu%d:invltlb"這樣的字符串初始化上面的intrname數(shù)組,這里的%d
- 為cpu的logical cpu id。
- *********************************************/
- 161 static u_long *ipi_preempt_counts[MAXCPU];
- 162 static u_long *ipi_ast_counts[MAXCPU];
- 163 u_long *ipi_invltlb_counts[MAXCPU];
- 164 u_long *ipi_invlrng_counts[MAXCPU];
- 165 u_long *ipi_invlpg_counts[MAXCPU];
- 166 u_long *ipi_invlcache_counts[MAXCPU];
- 167 u_long *ipi_rendezvous_counts[MAXCPU];
- 168 u_long *ipi_lazypmap_counts[MAXCPU];
- 169 static u_long *ipi_hardclock_counts[MAXCPU];
復(fù)制代碼 [數(shù)組cpu_apic_ids和apic_cpuids]:- /******************************************************************************************
- * #define MAX_APIC_ID 0xfe
- #define MAXCPU 32
- 下面兩個數(shù)組都是由函數(shù)assign_cpu_ids初始化的,該函數(shù)在初始化函數(shù)cpu_mp_start中被調(diào)用。
- 數(shù)組cpu_apic_ids的索引為logical cpu id,相應(yīng)數(shù)組元素的值為cpu的local APIC ID。
- 數(shù)組apic_cpuids的索引為cpu的local APIC ID,相應(yīng)數(shù)組元素的值為cpu的logical cpu id。
- ********************************************/
- 194 int cpu_apic_ids[MAXCPU];
- 195 int apic_cpuids[MAX_APIC_ID + 1];
復(fù)制代碼 [struct tdq對象中的tdq_ipipending成員]:- /******************************************************************************
- * tdq - per processor runqs and statistics. All fields are protected by the
- * tdq_lock. The load and lowpri may be accessed without to avoid excess
- * locking in sched_pickcpu();
- 對于SMP系統(tǒng):
- 每個cpu對應(yīng)的一個struct tdq數(shù)據(jù)對象,數(shù)組tdq_cpu以cpu的logical id為索引。
- static struct tdq tdq_cpu[MAXCPU];
- 對于非SMP系統(tǒng):
- 系統(tǒng)中只定義了一個struct tdq數(shù)據(jù)對象。
- static struct tdq tdq_cpu;
- tdq_ipipending:表示是否有掛起的IPI。
- *****************************************************/
- 225 struct tdq {
- 。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。
- 236 u_char tdq_ipipending; /* IPI pending. */
- 。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。
- 246 } __aligned(64);
復(fù)制代碼 根據(jù)之前sched_add函數(shù)的描述,當(dāng)把一個線程td添加到系統(tǒng)中某個cpu(假設(shè)為cpu5)的運行隊列時,就會檢查td是否能夠搶占當(dāng)前
正在cpu5上運行的線程,如果可以搶占,就要給cpu5發(fā)送一個IPI。
[摘取sched_add函數(shù)的部分代碼]:- /**************************************************************************************
- * Select the target thread queue and add a thread to it. Request
- * preemption or IPI a remote processor if required.
- 參數(shù)描述:
- td:標(biāo)識將要被添加到cpu運行隊列中的線程。
- flags:傳遞給函數(shù)sched_add的標(biāo)志,相關(guān)標(biāo)志需要結(jié)合上下文分析,這里暫且略過。
- **************************************/
- 2342
- 2343 void
- 2344 sched_add(struct thread *td, int flags)
- 2345 {
- 。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。
- /***************************************************************************************
- * 2365-2377:SMP系統(tǒng)
- *
- * Pick the destination cpu and if it isn't ours transfer to the
- * target cpu.
- 2370:函數(shù)sched_pickcpu為線程td挑選一個合適的cpu,局部變量smp_cpu保存了該
- cpu的logical cpu id,這里假設(shè)為5。
- 2371:函數(shù)sched_setcpu主要完成下面的工作:
- 將和線程td相關(guān)聯(lián)的struct td_sched數(shù)據(jù)對象的ts_cpu成員設(shè)置為smp_cpu。
- 并返回logical cpu id為smp_cpu的運行隊列,這里假設(shè)為&tdq_cpu[5]。
- ***********************************/
- 2365 #ifdef SMP
- 。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。
- 2370 smp_cpu = sched_pickcpu(td, flags);
- 2371 tdq = sched_setcpu(td, smp_cpu, flags);
- /************************************************************************
- * 2373-2376:
- 如果smp_cpu和當(dāng)前cpu的logical cpu id不相等,那么就調(diào)用函數(shù)
- tdq_notify檢查線程td是否能夠搶占當(dāng)前正在cpu logical id為smp_cpu
- 上運行的線程,如果可以,就發(fā)送一個IPI。
- *********************************************************/
- 2373 if (smp_cpu != PCPU_GET(cpuid)) {
- 2374 tdq_notify(tdq, td);
- 2375 return;
- 2376 }
- 。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。
- 2389 }
復(fù)制代碼 [摘取函數(shù)tdq_notify的部分代碼]:- /*******************************************************************************
- * Notify a remote cpu of new work. Sends an IPI if criteria are met.
- 對于logical cpu id為5的cpu,此時參數(shù)描述及相應(yīng)成員的取值如下:
- 參數(shù)描述:
- tdq:為&tdq_cpu[5]。
- td:已經(jīng)被添加到運行隊列tdq_cpu[5]的tdq_realtime隊列,tdq_timeshare隊列,
- tdq_idle隊列三個隊列之一中的線程。
- 成員取值描述:
- td->td_sched->ts_cpu的值為5。
- ***************************************************************************/
- 1011 static void
- 1012 tdq_notify(struct tdq *tdq, struct thread *td)
- 1013 {
- 。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。
- /************************************************************
- * 1018-1019:
- 如果struct tdq對象的tdq_ipipending成員非零,表示此時正在
- 發(fā)送IPI,此時直接返回。
- *****************************************/
- 1018 if (tdq->tdq_ipipending)
- 1019 return;
- 。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。
- /***************************************************************
- * 如果執(zhí)行到這里,就表示線程td將搶占線程ctd。
- * 1033:將struct tdq對象的tdq_ipipending成員設(shè)置為1。
- 1034:發(fā)送類型為IPI_PREEMPT的IPI。
- 變量cpu的值為5。
- ********************************************************/
- 1033 tdq->tdq_ipipending = 1;
- 1034 ipi_cpu(cpu, IPI_PREEMPT)
- 1035 }
復(fù)制代碼 從上面的描述中可以看出,調(diào)用函數(shù)ipi_cpu來發(fā)送一個IPI,函數(shù)ipi_cpu是內(nèi)核提供的用來發(fā)送IPI的接口。
[函數(shù)ipi_cpu]:- /************************************************************************
- * send an IPI to a specific CPU.
- 參數(shù)描述:
- cpu:接收IPI的cpu的logical cpu id,這里假設(shè)為5。
- ipi:
- 一般情況下為中斷向量號。
- 當(dāng)發(fā)送IPI_AST,IPI_PREEMPT,IPI_HARDCLOCK三個特殊的IPI時,對應(yīng)
- 的不是中斷向量號。
- 這里ipi的值為IPI_PREEMPT。
- 該函數(shù)實際上是函數(shù)ipi_send_cpu的一個簡單封裝。
- ********************************************/
- 1419 void
- 1420 ipi_cpu(int cpu, u_int ipi)
- 1421 {
- 1422
- /***********************************************************************
- * IPI_STOP_HARD maps to a NMI and the trap handler needs a bit
- * of help in order to understand what is the source.
- * Set the mask of receiving CPUs for this purpose.
- 1428-1429:
- #define IPI_STOP_HARD 252 Stop CPU with a NMI.
- 忽略之間的處理。
- 1432:ipi_send_cpu函數(shù)見下面的描述。
- *******************************/
- 1428 if (ipi == IPI_STOP_HARD)
- 1429 CPU_SET_ATOMIC(cpu, &ipi_nmi_pending);
- 1430
- 1431 CTR3(KTR_SMP, "%s: cpu: %d ipi: %x", __func__, cpu, ipi);
- 1432 ipi_send_cpu(cpu, ipi);
- 1433 }
復(fù)制代碼 [函數(shù)ipi_send_cpu]:- /***************************************************************************************
- * Send an IPI to specified CPU handling the bitmap logic.
- * 參數(shù)描述:
- cpu:接收IPI的cpu的logical cpu id,這里假設(shè)為5。
- ipi:
- 一般情況下為中斷向量號。
- 當(dāng)發(fā)送IPI_AST,IPI_PREEMPT,IPI_HARDCLOCK三個IPI時,對應(yīng)
- 的不是中斷向量號。
- 這里ipi的值為IPI_PREEMPT。
- 函數(shù)ipi_send_cpu的任務(wù)就是針對IPI_AST,IPI_PREEMPT,IPI_HARDCLOCK三個特殊的IPI
- 做相應(yīng)的處理。
- ***********************************
- 1190 static void
- 1191 ipi_send_cpu(int cpu, u_int ipi)
- 1192 {
- 1193 u_int bitmap, old_pending, new_pending;
- 1194
- 1195 KASSERT(cpu_apic_ids[cpu] != -1, ("IPI to non-existent CPU %d", cpu));
- /***********************************************************************************************************
- * 1197-1207:
- 如果發(fā)送的是IPI_AST,IPI_PREEMPT,IPI_HARDCLOCK三個特殊的IPI就進行相應(yīng)的處理。
-
- #define IPI_AST 0
- #define IPI_PREEMPT 1
- #define IPI_HARDCLOCK 2
- #define IPI_BITMAP_LAST IPI_HARDCLOCK 2
- #define IPI_IS_BITMAPED(x) ((x) <= IPI_BITMAP_LAST)
-
- 1197:
- 宏IPI_IS_BITMAPED檢查ipi是否為IPI_AST或者IPI_PREEMPT或者IPI_HARDCLOCK,如果是,宏的值就為真。
- 這里為IPI_IS_BITMAPED(IPI_PREEMPT) IPI_PREEMPT <= IPI_BITMAP_LAST,很明顯為真。
- 1198:變量bitmap為二進制10。
- 1199:此時重新設(shè)置變量ipi,將其設(shè)置為IPI_BITMAP_VECTOR,即中斷向量號249。
- 由此可以看出,當(dāng)發(fā)送IPI_AST,IPI_PREEMPT,IPI_HARDCLOCK三個特殊的IPI時,實際上發(fā)送的IPI的中斷向量號
- 都為IPI_BITMAP_VECTOR。
- 1200-1203,do-while循環(huán):
- 1201:old_pending保存的是當(dāng)前數(shù)組元素cpu_ipi_pending[5]的值。
- 1202:new_pending為將要賦值給數(shù)組元素cpu_ipi_pending[5]的新值。
- do_while循環(huán)一直執(zhí)行,直到old_pending和cpu_ipi_pending[cpu]的值相等時為止,此時函數(shù)atomic_cmpset_int
- 返回1,數(shù)組元素cpu_ipi_pending[cpu]的值被更新為new_pending。
-
- 因為APIC同時允許有兩個掛起的相同中斷,freebsd9.2貌似為了預(yù)防死鎖,一次只允許有一個掛起的中斷。
- 1205:如果old_pending非空,表示已經(jīng)發(fā)送了一個中斷向量號為IPI_BITMAP_VECTOR的IPI,但是cpu5還沒有處理。
- 此時直接返回。
- *************************************************/
- 1197 if (IPI_IS_BITMAPED(ipi)) {
- 1198 bitmap = 1 << ipi;
- 1199 ipi = IPI_BITMAP_VECTOR;
- 1200 do {
- 1201 old_pending = cpu_ipi_pending[cpu];
- 1202 new_pending = old_pending | bitmap;
- 1203 } while (!atomic_cmpset_int(&cpu_ipi_pending[cpu],
- 1204 old_pending, new_pending));
- 1205 if (old_pending)
- 1206 return;
- 1207 }
- /**************************************************************
- * 1208:
- logical cpu id是內(nèi)核用來標(biāo)識cpu的,但是發(fā)送IPI時,必須使用
- 指定cpu的local APIC ID,這里就要用到數(shù)組cpu_apic_ids。
- 數(shù)組元素cpu_apic_ids[5]的值為cpu5的local APIC ID。
-
- 此時,變量ipi已經(jīng)被正確設(shè)置,調(diào)用函數(shù)lapic_ipi_vectored
- 發(fā)送IPI。
- *************************************/
- 1208 lapic_ipi_vectored(ipi, cpu_apic_ids[cpu]);
- 1209 }
復(fù)制代碼 [函數(shù)lapic_ipi_vectored]-該函數(shù)構(gòu)造將要寫入到ICR中的值,下面再看看ICR的格式,假設(shè)其為0,一般情況下,Reserved
字段的值先讀出,然后保證寫入原值即可,這里假設(shè)Reserved字段的值為0:
icr.jpg (46.86 KB, 下載次數(shù): 85)
下載附件
2014-07-06 01:03 上傳
- /***************************************************************************
- * 參數(shù)描述:
- vector:中斷向量號,這里為IPI_BITMAP_VECTOR,即中斷向量號249。
- dest:cpu5的local APIC ID,這里假設(shè)為X,X為local APIC ID的二進制表示。
- *****************************
- 1441 void
- 1442 lapic_ipi_vectored(u_int vector, int dest)
- 1443 {
- /**********************************************************************
- * icrlo:將要寫入ICR低32位的值。
- destfield:將要寫入ICR高32位中Destination Field字段的值。
- 1449-1459:執(zhí)行完后,icrlo的值為0x000000F9。
- *******************************/
- 1444 register_t icrlo, destfield;
- 1445
- 1446 KASSERT((vector & ~APIC_VECTOR_MASK) == 0,
- 1447 ("%s: invalid vector %d", __func__, vector));
- 1448
- 1449 icrlo = APIC_DESTMODE_PHY | APIC_TRIGMOD_EDGE;
- 1450
- 1451 /*
- 1452 * IPI_STOP_HARD is just a "fake" vector used to send a NMI.
- 1453 * Use special rules regard NMI if passed, otherwise specify
- 1454 * the vector.
- 1455 */
- 1456 if (vector == IPI_STOP_HARD)
- 1457 icrlo |= APIC_DELMODE_NMI | APIC_LEVEL_ASSERT;
- 1458 else
- 1459 icrlo |= vector | APIC_DELMODE_FIXED | APIC_LEVEL_DEASSERT;
- /******************************************************************************************
- * 因為這里是發(fā)送給指定cpu的IPI,所以dest為目的cpu的local APIC ID。
- 1462-1464:IPI的目的地為僅包括發(fā)送此IPI的cpu,此時icrlo的值為0x000400F9。
- 1465-1467:IPI的目的地為系統(tǒng)中全部cpu,包括發(fā)送此IPI的cpu,此時icrlo的值為0x000800F9。
- 1468-1470:IPI的目的地為系統(tǒng)中除發(fā)送此IPI的cpu以外的cpu,此時icrlo的值為0x000C00F9。
-
- 如果switch語句從上面任意三個case中的一個跳出,destfield的值不變,即為0。
- 針對這里討論的情況,destfield的值為X,icrlo的值為0x000000F9。
- ************************************/
- 1460 destfield = 0;
- 1461 switch (dest) {
- 1462 case APIC_IPI_DEST_SELF:
- 1463 icrlo |= APIC_DEST_SELF;
- 1464 break;
- 1465 case APIC_IPI_DEST_ALL:
- 1466 icrlo |= APIC_DEST_ALLISELF;
- 1467 break;
- 1468 case APIC_IPI_DEST_OTHERS:
- 1469 icrlo |= APIC_DEST_ALLESELF;
- 1470 break;
- 1471 default:
- 1472 KASSERT((dest & ~(APIC_ID_MASK >> APIC_ID_SHIFT)) == 0,
- 1473 ("%s: invalid destination 0x%x", __func__, dest));
- 1474 destfield = dest;
- 1475 }
- 1476
- /*****************************************************************************************************
- * Wait for an earlier IPI to finish,檢查是否有更早的IPI沒有完成發(fā)送。
- #define BEFORE_SPIN 1000000
-
- ICR的字段Delivery Status:指示IPI的發(fā)送狀態(tài)。0:IPI已經(jīng)成功發(fā)送出去;1:還沒有完成IPI的發(fā)送。
- 函數(shù)lapic_ipi_wait執(zhí)行一個for循環(huán),不停的測試Delivery Status字段的值,如果在指定的時間內(nèi),該
- 字段的值變?yōu)?,就返回1;否則返回0,表示出現(xiàn)了某種問題。
- 這個指定的時間為BEFORE_SPIN * (指令pause的時鐘周期數(shù))。
- *******************************************/
- 1478 if (!lapic_ipi_wait(BEFORE_SPIN)) {
- 1479 if (panicstr != NULL)
- 1480 return;
- 1481 else
- 1482 panic("APIC: Previous IPI is stuck");
- 1483 }
- /*****************************************************************************************************
- * 1485:
- 函數(shù)lapic_ipi_raw完成IPI的發(fā)送,見下面的描述。
- ***********************/
- 1485 lapic_ipi_raw(icrlo, destfield);
- /*************************************************************************
- * 執(zhí)行到這里的話,IPI的發(fā)送已經(jīng)完成。
- *
- * 1487-1512之間的代碼只有在定義了DETECT_DEADLOCK才有意義,在有意義的
- 情況下,就是檢查一下此次發(fā)送的IPI是否完成發(fā)送。
- ***************************************/
- 1487 #ifdef DETECT_DEADLOCK
- 1488 /* Wait for IPI to be delivered. */ #define AFTER_SPIN 1000
- 1489 if (!lapic_ipi_wait(AFTER_SPIN)) {
- 1490 #ifdef needsattention
- 1491 /*
- 1492 * XXX FIXME:
- 1493 *
- 1494 * The above function waits for the message to actually be
- 1495 * delivered. It breaks out after an arbitrary timeout
- 1496 * since the message should eventually be delivered (at
- 1497 * least in theory) and that if it wasn't we would catch
- 1498 * the failure with the check above when the next IPI is
- 1499 * sent.
- 1500 *
- 1501 * We could skip this wait entirely, EXCEPT it probably
- 1502 * protects us from other routines that assume that the
- 1503 * message was delivered and acted upon when this function
- 1504 * returns.
- 1505 */
- 1506 printf("APIC: IPI might be stuck\n");
- 1507 #else /* !needsattention */
- 1508 /* Wait until mesage is sent without a timeout. */
- 1509 while (lapic->icr_lo & APIC_DELSTAT_PEND)
- 1510 ia32_pause();
- 1511 #endif /* needsattention */
- 1512 }
- 1513 #endif /* DETECT_DEADLOCK */
- 1514 }
復(fù)制代碼 [函數(shù)lapic_ipi_raw]:- /************************************************************************************
- * 參數(shù)描述:
-
- icrlo:將要寫到ICR低32位的值,針對這里討論的情況,值為0x000000F9。
-
- dest:目的cpu的local APIC ID或者為0,針對這里討論的情況,值為X。
- *************************/
- 1407 void
- 1408 lapic_ipi_raw(register_t icrlo, u_int dest)
- 1409 {
- 1410 register_t value, saveintr;
- 1411
- 1412 /* XXX: Need more sanity checking of icrlo? */
- 1413 KASSERT(lapic != NULL, ("%s called too early", __func__));
- 1414 KASSERT((dest & ~(APIC_ID_MASK >> APIC_ID_SHIFT)) == 0,
- 1415 ("%s: invalid dest field", __func__));
- 1416 KASSERT((icrlo & APIC_ICRLO_RESV_MASK) == 0,
- 1417 ("%s: reserved bits set in ICR LO register", __func__));
- 1418
- /***********************************************************************************
- * Set destination in ICR HI register if it is being used.
-
- 1420:函數(shù)intr_disable將當(dāng)前EFLAGS寄存器的值保存到變量中saveintr,之后清
- EFLAGS寄存器的IF標(biāo)志,表示此時禁止中斷。
-
- 針對這里討論的情況,將執(zhí)行1421-1426之間的語句。
- 變量lapic請參考"內(nèi)核如何實現(xiàn)IA32中斷處理"中的描述。
- 通過變量lapic訪問cpu5的local APIC寄存器組:
- lapic->icr_hi:訪問ICR高32位。
-
- 1422-1425:ICR高32位中的bit24-31被設(shè)置為X,bit0-23保持原來的值。
-
- 執(zhí)行完后ICR中Destination Field字段的值為X,即這個IPI將發(fā)送給cpu5。
- ******************************************/
- 1420 saveintr = intr_disable();
- 1421 if ((icrlo & APIC_DEST_MASK) == APIC_DEST_DESTFLD) {
- 1422 value = lapic->icr_hi;
- 1423 value &= ~APIC_ID_MASK;
- 1424 value |= dest << APIC_ID_SHIFT;
- 1425 lapic->icr_hi = value;
- 1426 }
- /******************************************************************************************
- * 通過變量lapic訪問cpu5的local APIC寄存器組:
- lapic->icr_lo:訪問ICR低32位。
- 1429-1431:執(zhí)行完后,value的值為0x000000F9。
-
- 1432:這個賦值操作就相當(dāng)于對ICR低32位執(zhí)行了一個寫操作,ICR的Vector字段的值為0xF9。
-
- 此時,已經(jīng)向cpu5發(fā)出了一個IPI,該IPI的中斷向量號為IPI_BITMAP_VECTOR,當(dāng)cpu5
- 接收到這個中斷時,就按照"內(nèi)核如何實現(xiàn)IA32中斷處理"中最后描述的中斷處理機制進行處理。
- 1432:用saveintr恢復(fù)EFLAGS寄存器。
- ****************************************/
- 1428 /* Program the contents of the IPI and dispatch it. */
- 1429 value = lapic->icr_lo;
- 1430 value &= APIC_ICRLO_RESV_MASK;
- 1431 value |= icrlo;
- 1432 lapic->icr_lo = value;
- 1433 intr_restore(saveintr);
- 1434 }
復(fù)制代碼 |
|