Linux0.11內核--進程調度分析之1.初始化

来源:http://www.cnblogs.com/joey-hua/archive/2016/06/18/5596746.html
-Advertisement-
Play Games

【版權所有,轉載請註明出處。出處:http://www.cnblogs.com/joey-hua/p/5596746.html 】 首先看main.c里的初始化函數main函數裡面有個函數是對進程調度的初始化,sched_init()函數,次函數在sched.c中實現: 首先初始化任務0的TTS,F ...


【版權所有,轉載請註明出處。出處:http://www.cnblogs.com/joey-hua/p/5596746.html

首先看main.c里的初始化函數main函數裡面有個函數是對進程調度的初始化,sched_init()函數,次函數在sched.c中實現:

// 調度程式的初始化子程式。
void sched_init (void)
{
  int i;
  struct desc_struct *p;	// 描述符表結構指針。

  if (sizeof (struct sigaction) != 16)	// sigaction 是存放有關信號狀態的結構。
    panic ("Struct sigaction MUST be 16 bytes");
  // 設置初始任務(任務0)的任務狀態段描述符和局部數據表描述符(include/asm/system.h,65)。
  set_tss_desc (gdt + FIRST_TSS_ENTRY, &(init_task.task.tss));
  set_ldt_desc (gdt + FIRST_LDT_ENTRY, &(init_task.task.ldt));
  // 清任務數組和描述符表項(註意i=1 開始,所以初始任務的描述符還在)。
  p = gdt + 2 + FIRST_TSS_ENTRY;
  for (i = 1; i < NR_TASKS; i++)
    {
      task[i] = NULL;
      p->a = p->b = 0;
      p++;
      p->a = p->b = 0;
      p++;
    }
  /* Clear NT, so that we won't have troubles with that later on */
  /* 清除標誌寄存器中的位NT,這樣以後就不會有麻煩 */
  // NT 標誌用於控製程序的遞歸調用(Nested Task)。當NT 置位時,那麼當前中斷任務執行
  // iret 指令時就會引起任務切換。NT 指出TSS 中的back_link 欄位是否有效。
  __asm__ ("pushfl ; andl $0xffffbfff,(%esp) ; popfl");	// 複位NT 標誌。
  ltr (0);			// 將任務0 的TSS 載入到任務寄存器tr。
  lldt (0);			// 將局部描述符表載入到局部描述符表寄存器。
  // 註意!!是將GDT 中相應LDT 描述符的選擇符載入到ldtr。只明確載入這一次,以後新任務
  // LDT 的載入,是CPU 根據TSS 中的LDT 項自動載入。
  // 下麵代碼用於初始化8253 定時器。
  outb_p (0x36, 0x43);		/* binary, mode 3, LSB/MSB, ch 0 */
  outb_p (LATCH & 0xff, 0x40);	/* LSB */// 定時值低位元組。
  outb (LATCH >> 8, 0x40);	/* MSB */// 定時值高位元組。
  // 設置時鐘中斷處理程式句柄(設置時鐘中斷門)。
  set_intr_gate (0x20, &timer_interrupt);
  // 修改中斷控制器屏蔽碼,允許時鐘中斷。
  outb (inb_p (0x21) & ~0x01, 0x21);
  // 設置系統調用中斷門。
  set_system_gate (0x80, &system_call);
}

首先初始化任務0的TTS,FIRST_TSS_ENTRY為4,表示在描述符表的索引是4。因為gdt是desc_struct類型為8個位元組,剛好是一個描述符的長度,所以這裡的gdt+4可以理解為gdt[4]。剛好對應的是TSS0。

描述符表的內容如下:

0-沒有用nul,1-代碼段cs,2-數據段ds,3-系統段syscall,4-任務狀態段TSS0,5-局部表LTD0,6-任務狀態段TSS1,等。

//// 在全局表中設置任務狀態段/局部表描述符。
// 參數:n - 在全局表中描述符項n 所對應的地址;addr - 狀態段/局部表所在記憶體的基地址。
// type - 描述符中的標誌類型位元組。
// %0 - eax(地址addr);%1 - (描述符項n 的地址);%2 - (描述符項n 的地址偏移2 處);
// %3 - (描述符項n 的地址偏移4 處);%4 - (描述符項n 的地址偏移5 處);
// %5 - (描述符項n 的地址偏移6 處);%6 - (描述符項n 的地址偏移7 處);
#define _set_tssldt_desc(n,addr,type) \
__asm__ ( "movw $104,%1\n\t" \	// 將TSS 長度放入描述符長度域(第0-1 位元組)。
"movw %%ax,%2\n\t" \		// 將基地址的低字放入描述符第2-3 位元組。
  "rorl $16,%%eax\n\t" \	// 將基地址高字移入ax 中。
  "movb %%al,%3\n\t" \		// 將基地址高字中低位元組移入描述符第4 位元組。
  "movb $" type ",%4\n\t" \	// 將標誌類型位元組移入描述符的第5 位元組。
  "movb $0x00,%5\n\t" \		// 描述符的第6 位元組置0。
  "movb %%ah,%6\n\t" \		// 將基地址高字中高位元組移入描述符第7 位元組。
  "rorl $16,%%eax" \		// eax 清零。
  ::"a" (addr), "m" (*(n)), "m" (*(n + 2)), "m" (*(n + 4)),
  "m" (*(n + 5)), "m" (*(n + 6)), "m" (*(n + 7)))
//// 在全局表中設置任務狀態段描述符。
// n - 是該描述符的指針(向量);addr - 是描述符中的基地址值。任務狀態段描述符的類型是0x89。
#define set_tss_desc(n,addr) _set_tssldt_desc(((char *) (n)),addr, "0x89")
//// 在全局表中設置局部表描述符。
// n - 是該描述符的指針(向量);addr - 是描述符中的基地址值。局部表描述符的類型是0x82。
#define set_ldt_desc(n,addr) _set_tssldt_desc(((char *) (n)),addr, "0x82")

因為TSS最小尺寸是104位元組,所以第一句是把長度104賦值給TTS0描述符的第0-1位元組,描述符的格式如 描述符格式 ;第二句是把ax也就是addr也就是任務聯合的第一個任務的tss地址賦值給*(n+2)處,因為是movw字,所以也就是描述符的第2-3位元組處。接下來填充第4位元組,然後把類型type填充到第5位元組,最後把剩餘的位元組填充。

初始化任務0的ldt的方法也是類似,好了,這裡初始化完成任務0的TSS和LDT。

sched_init接下來是清空除了任務0的所有任務的數組和對應的描述符,這個好理解。

下麵是載入任務0的TSS到任務寄存器tr,載入ldt到局部描述符表寄存器ldtr,sched.h:

/*
* 尋找第1 個TSS 在全局表中的入口。0-沒有用nul,1-代碼段cs,2-數據段ds,3-系統段syscall
* 4-任務狀態段TSS0,5-局部表LTD0,6-任務狀態段TSS1,等。見head.s
*/
// 全局表中第1 個任務狀態段(TSS)描述符的選擇符索引號。
#define FIRST_TSS_ENTRY 4
// 全局表中第1 個局部描述符表(LDT)描述符的選擇符索引號。
#define FIRST_LDT_ENTRY (FIRST_TSS_ENTRY+1)
// 巨集定義,計算在全局表中第n 個任務的TSS 描述符的索引號(選擇符)。
#define _TSS(n) ((((unsigned long) n)<<4)+(FIRST_TSS_ENTRY<<3))
// 巨集定義,計算在全局表中第n 個任務的LDT 描述符的索引號。
#define _LDT(n) ((((unsigned long) n)<<4)+(FIRST_LDT_ENTRY<<3))
// 巨集定義,載入第n 個任務的任務寄存器tr。
#define ltr(n) __asm__( "ltr %%ax":: "a" (_TSS(n)))
// 巨集定義,載入第n 個任務的局部描述符表寄存器ldtr。
#define lldt(n) __asm__( "lldt %%ax":: "a" (_LDT(n)))

LDTR局部描述符寄存器:16位,高13為存放LDT在GDT中的索引值。

所以FIRST_LDT_ENTRY要左移3位,(((unsigned long) n)<<4)不太好理解,因為先要去掉左移的3位,所以實際值是n<<1,也就是2n。最終的值相當於FIRST_LDT_ENTRY+2n。這樣就好理解了,因為每個任務都有兩個描述符項。

這裡要註意:只明確載入這一次,以後新任務LDT 的載入,是CPU 根據TSS 中的LDT 項自動載入。

接下來是初始化定時器,沒什麼好說的。

接下來兩句最關鍵了,進程調度的引發的誘因就是在下麵初始化的:

  // 設置時鐘中斷處理程式句柄(設置時鐘中斷門)。
  set_intr_gate (0x20, &timer_interrupt);
  // 修改中斷控制器屏蔽碼,允許時鐘中斷。
  outb (inb_p (0x21) & ~0x01, 0x21);

第一句在系統調用機制分析中有講到,是設置中斷門的,所以這裡就是把system_call.s中的函數timer_interrupt和中斷號0x20關聯起來,下麵一句代碼參考 時鐘中斷 開啟了時鐘中斷也就是0x20號中斷,也就是說時鐘每滴答(10ms)一下就會調用timer_interrupt函數。

到這裡,進程調度的初始化就結束了。


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • ...
  • 一.概述 * 鬧鐘功能概述:添加鬧鐘,刪除鬧鐘 * 思路: * 1.給一個button添加點擊監聽,用於添加鬧鐘 * 2.提供一個視窗進行鬧鐘時間的選擇 * 3.數據保存:對鬧鐘的數據進行保存 * 4.數據讀取:打開app的時候對鬧鐘的數據進行讀取,以便保留以前設置的鬧鐘 * 5.對鬧鐘進行刪除操作 ...
  • 【版權所有,轉載請註明出處。出處:http://www.cnblogs.com/joey-hua/p/5597705.html 】 Linux內核因為使用了記憶體分頁機制,所以相對來說好理解些。因為記憶體分頁就是為了方便管理記憶體。 說到記憶體分頁,最根部的要屬頁目錄表了,head.h中: 然後再看head ...
  • “階段一”是指我第一次系統地學習Android開發。這主要是對我的學習過程作個記錄。 最近學到用AsyncTask來處理有關網路的操作。雖然代碼看上去不是很複雜,但仍有很多地方有疑惑。所以研讀了一下API文檔,在這裡把我學到的和練習的代碼展示出來。如有錯誤,歡迎指出! 一、關於AsyncTask的< ...
  • 接著上篇《Android 採用get方式提交數據到伺服器》,本文來實現採用post方式提交數據到伺服器 首先對比一下get方式和post方式: 修改佈局: 添加代碼: ...
  • 【版權所有,轉載請註明出處。出處:http://www.cnblogs.com/joey-hua/p/5596830.html 】 上一篇說到進程調度歸根結底是調用timer_interrupt函數,在system_call.s中: 前面一堆push指令保存當前的寄存器,然後在ret_from_sy ...
  • 首先搭建模擬web 伺服器,新建動態web項目,servlet代碼如下: 再新建一個jsp頁面 新建android項目,頁面佈局: 代碼如下: 添加許可權:android.permission.INTERNET 運行項目後點擊按鈕後提示錯誤: 06-18 21:08:16.237: W/System. ...
  • 文件命名規範: 1. 項目統一使用類首碼ZY。 2. 分類命名+後面統一使用ZYExtension,例:NSDictionary+ZYExtension.h,常用分類定義在內部並寫好文檔註釋。如果功能性分類內部方法較多可以考慮按功能命名。 3. model文件可按伺服器介面名或欄位名命名,view、 ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...