歡迎來到Linux教程網
Linux教程網
Linux教程網
Linux教程網
Linux教程網 >> Linux綜合 >> Linux內核 >> 基於PowerPC的Linux內核之旅:__secondary_start(start_here)-下

基於PowerPC的Linux內核之旅:__secondary_start(start_here)-下

日期:2017/3/1 11:08:33   编辑:Linux內核
上篇中(http://www.linuxidc.com/Linux/2011-11/46582.htm)介紹了基於PowerPC的Linux第二階段啟動過程的一部分,由於MMU的初始化涉及的內容較多,而且代碼量很大,所以這部分分為上下兩部。本部分繼續闡述MMU硬件的初始化和最終真正使能MMU的過程。

在開始之前,先指出前面文章出現的一個錯誤,在對mmu_off函數中的RFI指令的介紹時,我簡單的認為是中斷返回,但後來想想,CPU初始化時,中斷還沒有使能,所以中斷返回的說法是不正確的,查了下資料,原來使用RFI指令也可以做程序跳轉使用,使用RFI進行程序跳轉的好處是,程序跳轉後將自動執行isync指令,以保證指令空間的同步,在Linux的初始化階段,使用RFI指令進行程序跳轉比較常見,這裡的RFI指令與中斷返回是沒有任何關系的。造成誤解請見諒。

另外,最近被工作上的事情困擾的有些力不從心了,感覺這篇對MMU的硬件初始化分析寫的極其的爛,待以後收拾了心情,我一定會加以改進的,當然,也希望高手能不吝指教,就當交個朋友吧。

先來看一下MMU_init_hw的詳細代碼(位於mm/ppc_mmu_32.c):

  1. void __init MMU_init_hw(void)
  2. {
  3. unsigned int hmask, mb, mb2;
  4. unsigned int n_hpteg, lg_n_hpteg;
  5. /*定義於hash_low_32.S,填充和清除Hash表*/
  6. extern unsigned int hash_page_patch_A[];
  7. extern unsigned int hash_page_patch_B[], hash_page_patch_C[];
  8. extern unsigned int hash_page[];
  9. extern unsigned int flush_hash_patch_A[], flush_hash_patch_B[];
  10. if (!mmu_has_feature(MMU_FTR_HPTE_TABLE)) {
  11. /*在hash_page的開始處放置blr指令,因為在603處理器中仍能接收到DSI(Data Storage Interrupt)異常*/
  12. hash_page[0] = 0x4e800020;
  13. flush_icache_range((unsigned long) &hash_page[0],
  14. (unsigned long) &hash_page[1]); /*清空指令cache*/
  15. return;
  16. }
  17. if ( ppc_md.progress ) ppc_md.progress("hash:enter", 0x105);
  18. #define LG_HPTEG_SIZE 6 /* 每個PTEG為64個字節 */
  19. #define SDR1_LOW_BITS ((n_hpteg - 1) >> 10)
  20. #define MIN_N_HPTEG 1024 /* min 64kB hash table */
  21. /*允許每頁內存都有一個HPTE*/
  22. n_hpteg = total_memory / (PAGE_SIZE * 8);
  23. if (n_hpteg < MIN_N_HPTEG)
  24. n_hpteg = MIN_N_HPTEG;
  25. lg_n_hpteg = __ilog2(n_hpteg);
  26. if (n_hpteg & (n_hpteg - 1)) {
  27. ++lg_n_hpteg; /* round up if not power of 2 */
  28. n_hpteg = 1 << lg_n_hpteg;
  29. }
  30. Hash_size = n_hpteg << LG_HPTEG_SIZE;
  31. /*為哈希表申請內存地址,這兩步就類似於malloc和memset*/
  32. if ( ppc_md.progress ) ppc_md.progress("hash:find piece", 0x322);
  33. Hash = __va(memblock_alloc_base(Hash_size, Hash_size,
  34. __initial_memory_limit_addr));
  35. cacheable_memzero(Hash, Hash_size);
  36. _SDR1 = __pa(Hash) | SDR1_LOW_BITS;
  37. Hash_end = (struct hash_pte *) ((unsigned long)Hash + Hash_size);
  38. /*Patch up the instructions in hash_low_32.S:create_hpte*/
  39. if ( ppc_md.progress ) ppc_md.progress("hash:patch", 0x345);
  40. Hash_mask = n_hpteg - 1;
  41. hmask = Hash_mask >> (16 - LG_HPTEG_SIZE);
  42. mb2 = mb = 32 - LG_HPTEG_SIZE - lg_n_hpteg;
  43. if (lg_n_hpteg > 16)
  44. mb2 = 16 - LG_HPTEG_SIZE;
  45. hash_page_patch_A[0] = (hash_page_patch_A[0] & ~0xffff)
  46. | ((unsigned int)(Hash) >> 16);
  47. hash_page_patch_A[1] = (hash_page_patch_A[1] & ~0x7c0) | (mb << 6);
  48. hash_page_patch_A[2] = (hash_page_patch_A[2] & ~0x7c0) | (mb2 << 6);
  49. hash_page_patch_B[0] = (hash_page_patch_B[0] & ~0xffff) | hmask;
  50. hash_page_patch_C[0] = (hash_page_patch_C[0] & ~0xffff) | hmask;
  51. /*確保patch過的地方是否從數據cache中保存,並清除指令cache*/
  52. flush_icache_range((unsigned long) &hash_page_patch_A[0],
  53. (unsigned long) &hash_page_patch_C[1]);
  54. /*Patch up the instructions in hash_low_32.S:flush_hash_page*/
  55. flush_hash_patch_A[0] = (flush_hash_patch_A[0] & ~0xffff)
  56. | ((unsigned int)(Hash) >> 16);
  57. flush_hash_patch_A[1] = (flush_hash_patch_A[1] & ~0x7c0) | (mb << 6);
  58. flush_hash_patch_A[2] = (flush_hash_patch_A[2] & ~0x7c0) | (mb2 << 6);
  59. flush_hash_patch_B[0] = (flush_hash_patch_B[0] & ~0xffff) | hmask;
  60. flush_icache_range((unsigned long) &flush_hash_patch_A[0],
  61. (unsigned long) &flush_hash_patch_B[1]);
  62. if ( ppc_md.progress ) ppc_md.progress("hash:done", 0x205);
  63. }
Copyright © Linux教程網 All Rights Reserved