主頁 >  其他 > 深入Linux內核(記憶體篇)—頁表映射分頁

深入Linux內核(記憶體篇)—頁表映射分頁

2020-10-14 07:00:52 其他

深入Linux內核(記憶體篇)—頁表映射

  • 一、分頁
    • 1.1 頁表存在哪里?
    • 1.2 頁表長啥樣?
    • 1.3 分頁機制如何完成行程地址空間切換?
    • 1.4 實際使用的分頁機制
    • 1.5 多級頁表的缺點
    • 1.6 Translation Lookside Buffer
    • 1.7 頁表多大合適?
  • 二、X86中的分頁
    • 2.1 32-bit Paging
    • 2.2 32-bit Paging頁表長啥樣?
    • 2.3 4-Level Paging
  • 三、ARM中的分頁
    • 3.1 ARMv7 Paging
    • 3.2 ARMv7 4KB Paging頁表長啥樣?
    • 3.3 ARMv8 分頁配置
    • 3.4 ARMv8 Paging
  • 四、Kernel中的分頁
    • 4.1 X86分頁
    • 4.1 ARMv7分頁
    • 4.2 ARMv8分頁

作業系統的核心任務是對系統資源的管理,而重中之重的是對CPU和記憶體的管理,為了使行程擺脫系統記憶體的制約,用戶行程運行在虛擬記憶體之上,每個用戶行程都擁有完整的虛擬地址空間,互不干涉,

而實作虛擬記憶體的關鍵就在于建立虛擬地址(Virtual Address,VA)與物理地址(Physical Address,PA)之間的關系,因為無論如何資料終究要存盤到物理記憶體中才能被記錄下來,
如下圖所示,行程1和行程2擁有完整的虛擬地址空間,虛擬地址空間分為了用戶空間和內核空間,對于不同的行程面對的都是同一個內核,其內核空間的地址對于的物理地址都是一樣的,因而行程1和行程2中內核空間的VA K地址都映射到了物理記憶體的PA K地址,而不同的行程的用戶空間是不同的,行程1和行程2相同的虛擬地址VA 1和VA 2分別映射到了不同的物理地址PA 1和PA 2上,
在這里插入圖片描述
而虛擬地址到物理地址映射關系的實作可以稱之為地址轉換(Address Translation)
為了實作上述地址轉換,作業系統需要借助硬體的幫助,即記憶體管理單元(Memory Management Unit,MMU)的幫助,
對于MMU應當有如下功能:

要求說明
特權模式區分內核空間和用戶空間,用戶行程無法直接訪問內核地址空間
基址/界限暫存器記錄地址轉換基址的暫存器,用于尋址地址轉換映射表
地址轉換完成地址轉換程序
檢查越界完成地址轉換程序中,可以檢查訪問是否越界
基址/界限暫存器特權操作指令用于修改地址轉換基址的暫存器,可以保證不同行程訪問的映射表不同,從而映射的結果也不同
觸發例外發生越權,越界訪問時,可以觸發例外通知作業系統
例外處理特權操作指令作業系統用于處理記憶體訪問例外的入口

MMU配合作業系統完成了諸多功能:

  • 用戶空間和內核空間,通過特權模式劃分了內核空間和用戶空間,用戶空間無法直接訪問內核空間,必須通過某些手段(系統呼叫,例外,中斷等)切換到特權模式才能間接訪問內核,
  • 地址轉換,通過基址/界限暫存器記錄的轉換映射表基址,結合虛擬地址,可以完成地址轉換的功能,從而實作通過虛擬地址訪問到物理地址,
  • 行程獨立的虛擬地址空間,通過基址/界限暫存器的訪問指令,在行程切換時修改基址/界限暫存器的值,從而使MMU在做地址轉換時找到各個行程對應的地址映射表,從而實作不同行程虛擬地址完全獨立,
  • 缺頁例外,對于行程申請的記憶體,并不需要在其申請記憶體時即建立地址轉換映射表,同時分配對應的物理空間,而是在行程真正訪問記憶體地址時,MMU上報缺頁例外再分配對應的物理空間,當然虛擬地址到物理地址映射表中的一些標志區可以實作更多的缺頁例外型別,例如讀寫權限錯誤,特權錯誤,越界錯誤等例外,

本文重點關注地址轉換,而地址轉換的核心是頁表映射,

一、分頁

分頁即將記憶體劃分為固定長度的單元,每個單元就是一頁,
對于虛擬地址空間,分頁機制將地址空間分割成固定大小的單元,每個單元稱為一頁,對于物理地址空間,物理記憶體被抽象成固定大小的單元,每個單元稱為頁幀(frame),通過分頁管理記憶體可以避免分段帶來的記憶體外碎片問題,
分頁管理記憶體的核心問題是虛擬地址頁到物理地址頁幀的映射關系,

虛擬地址到物理地址的轉換可以抽象簡化成下圖,假設地址是32位的,
在這里插入圖片描述
為了將虛擬地址轉換成物理地址,將虛擬地址分割成兩部分:

  1. 虛擬頁面號,高31-X位組成,VPN(virtual page number);
  2. 虛擬地址偏移,低X位組成,VA Offset(virtual address offset);

物理地址也抽象成兩部分:

  1. 物理頁幀號,高31-X位組成,PFN(physical frame number);
  2. 物理地址偏移,低X位組成,PA Offset(physical address offset);

虛擬頁面號VPN用于索引物理頁幀號PFN,VPN索引PFN的程序就是地址轉換的核心,VA offset通常就是PA offset,即PFN + VA offset就是最終物理地址,

所以,可以說分頁機制的核心就是VPN到PFN的映射,而VPN到PFN的映射關系是通過頁表記錄的,MMU通過頁表記錄的映射關系完成VPN到PFN的轉換,即找到了頁表就找到了物理地址

1.1 頁表存在哪里?

以32位地址空間為例,分頁大小為4KB(最常用的分頁大小),上述抽象例子中的X為12,那么VPN長度就是20bit,偏移量為12bit,
20bit的VPN意味著作業系統需要2^20個地址轉換映射,假設每個轉換映射需要4Byte空間存盤,那么所有映射關系需要4MB空間,
開篇我們提到,行程的虛擬地址到物理地址的轉換是不同的,所以每個行程的映射關系也是不同的,就是說每個行程都需要4MB的空間來存盤頁表,如果作業系統運行100個行程,則需要400MB空間,
可見頁表所需要的空間是很大的,所以頁表都存盤在物理記憶體中,即MMU通將虛擬地址轉換為物理地址,需要訪問物理記憶體中對應的頁表,
當然頁表占用物理記憶體大的問題還是需要解決的,這是分頁相對于分段的一個劣勢,解決方案是多級頁表配合缺頁例外的方式,后面再詳細介紹多級頁表的機制,

1.2 頁表長啥樣?

頁表是如何完成VPN到PFN的轉換的,要知道這個問題就得清楚頁表的基本內容,即頁表記錄了什么資訊,
頁表的作用就是通過VPN找到PFN,那么頁表最基本的組成部分需要包含如下內容:

  • PFN物理頁幀號;
  • 有效位(valid),用于標記頁面是否有效;
  • 存在位(present),指示該頁是否存在于物理記憶體,用于頁面換入換出(swap);
  • 特權標記,指示頁面訪問的特權等級;
  • Dirty位,寫操作時設定該位,表示頁面被寫過,頁面交換時使用;

1.3 分頁機制如何完成行程地址空間切換?

每個行程都擁有自己獨立的地址空間,行程切換時地址空間也會切換,不同行程都擁有自己的一套頁表,因而即使兩個行程虛擬地址相同,映射的物理地址也是不同的,
切換地址空間相當于控制MMU訪問不同行程擁有的頁表,MMU找到了頁表就找到了物理地址,
通常CPU會提供若干暫存器供作業系統使用,用于為MMU指示頁表的基地址,
如下圖所示,行程切換時,只需要設定頁表基址暫存器即可完成頁表的切換,也就完成了行程地址空間的切換,
所以CPU會為作業系統提供頁表基址暫存器用于行程地址空間的切換,

X86體系架構提供的暫存器是CR3(Control Register 3);ARM-v7體系架構提供的暫存器是協處理器CP15暫存器TTBR(Tranlation Table Base Register);ARM-v8體系架構提供的暫存器是系統暫存器TTBR(Tranlation Table Base Register),

在這里插入圖片描述

1.4 實際使用的分頁機制

考慮到分頁機制占用記憶體過多的問題,實際的分頁機制是多級分頁,
以二級頁表為例,如下圖所示,MMU通過頁表基址暫存器配合虛擬地址中的PGD index(Page Global Directory)找到一級頁表,通過一級頁表配合虛擬地址中的PTE index(Page Table Entry)找到二級頁表,通過二級頁表配合虛擬地址中Offset找到物理地址,
多級頁表要做到節省記憶體,還需要配合缺頁例外,行程往往只需將一級頁表保持到記憶體中,二級頁表在缺頁例外時再分配,
下圖示例中,一級頁表一共4096項(212),二級頁表一共512項(29),因此行程頁表可以只使用4096 X 4Byte空間即可,如果使用一級頁表,則需要2097152 X 4Byte空間,因此多級頁表帶來的最大好處就是降低了記憶體空間的占用
在這里插入圖片描述

1.5 多級頁表的缺點

多級頁表帶來了好處,降低了作業系統行程管理,記憶體管理對記憶體空間的占用,當然計算機領域總是沒有那么完美的方案,多級分頁也逃避不了這個宿命,獲得了空間的優勢,也帶來時間上的損失,
多級分頁時間上的損失主要體現在如下幾個方面:

  • 用時下發的耗時:對于子行程寫時復制(COW)技術大家比較熟悉,其實多級頁表也利用了類似的思想,多級頁表的后幾級頁表映射關系沒有存在記憶體中,MMU地址轉換中發現頁表不存在需要向作業系統上報缺頁例外,作業系統需要在缺頁例外中下發頁表到記憶體;
  • 額外的記憶體訪問:MMU進行地址轉換需要通過頁表基址暫存器找到一級頁表,再依次找到下級頁表,所有的頁表都存放在記憶體中,訪問記憶體是需要額外的時間消耗的,相對于CPU對暫存器的訪問,Cache的訪問速度而言,記憶體的訪問速度是災難性的,何況還是多次訪問,當然額外的記憶體訪問本身是分頁機制相對分段機制的缺陷,一級頁表映射也存在這樣的缺陷,只是多級頁表映射將這個缺點再次放大,

1.6 Translation Lookside Buffer

Translation Lookside Buffer簡稱TLB,按其真實作用應當翻譯為地址轉換快取
方才抨擊了多級頁表映射基址,提出了它可能導致系統變慢的缺點,那么如何解決這一問題呢?如果使MMU做頁表轉換時不訪問記憶體,是不是就解決問題了?TLB就是干這個事的,
TLB之所以可以解決這個問題是因為TLB是Cache,它將CPU訪問記憶體替換為CPU訪問Cache,也就是說MMU做頁表轉換時不再訪問記憶體的頁表,而是訪問快取在TLB中的頁表,因而降低了時間的消耗,
TLB要實作這個替換,其需要實作的基本作業原理是:

  1. 從虛擬地址中提取頁號(VPN),檢查TLB是否有該VPN的轉換映射,
  2. 如果有,則表示TLB命中(TLB hit),意味著從TLB中找到VPN對應的物理頁框號(PFN),PFN與虛擬地址的偏移量組成成物理地址(PA),
  3. 如果沒有,表示TLB未命中(TLB miss),則需要處理TBL miss,
  4. TLB miss處理有兩種方法,一種是硬體處理,一種是軟體處理,硬體處理TLB miss會自動更新TLB,軟體處理則是由硬體拋出一個TLB miss例外,軟體進入例外處理程式,查找物理頁表中轉換映射,再由指令更新TLB,并從例外中回傳,
  5. 軟體處理TLB miss例外與其他例外不同,例外處理回傳后,應繼續執行陷入例外之后的那條指令,而TLB miss例外處理回傳后,從導致陷入例外的執行開始執行,這樣保證TLB一定命中,

誠然,TLB是好,但是也引入了一些麻煩事(既然是Cache,就有一致性問題):行程切換時TLB如何處理?TLB表項滿了如何處理?mmap映射的記憶體被munmap解除TLB怎么處理?……
針對這些話題本文不做深入探討,可以閱讀另一篇為其量身定做的博文《深入Linux內核(記憶體篇)—TLB》,

1.7 頁表多大合適?

大頁表的好處:

  • 省記憶體:可以解決分頁機制占用記憶體的問題,取得和多級頁表一樣節省記憶體的效果;
  • 對TLB友好:大頁表意味著地址轉換時需要更少的頁表映射表項,頁表映射表項少了意味著TLB快取的表項少,這樣就提高了TLB的命中率;

大頁表的壞處:

  • 記憶體內碎片:作業系統申請記憶體時總是申請一大塊記憶體,哪怕實際只需要很小的記憶體,導致大頁記憶體得不到充分利用;而且記憶體很快會被這些大頁侵占,

顯然小頁表的好處和壞處正好與大頁表對立,
因此頁表不是越大越好,也不是越小越好,找到折中的大小是才最適合,通常作業系統的使用的頁大小是4KB,

各種體系架構的CPU都支持很多種頁大小,因此實際頁表的應用可能會更“聰明”,用戶行程在請求地址空間時,可以因需求選擇合適的頁大小,這樣既可以滿足資料的存放,同時占用更少的TLB表項,一個典型的例子,DPDK使用了1GB的大頁記憶體,這樣DPDK行程的頁表映射只占用一個TLB表項,在行程執行程序中杜絕了TLB miss情況的發生,保障了性能,

二、X86中的分頁

X86中定義分頁即將每個線性地址轉換為物理地址,并確定對于每個轉換,允許對線性地址的何種訪問(地址的訪問權限)以及用于此類訪問的快取型別(地址的記憶體型別),

X86支持如下四種分頁模式:
在這里插入圖片描述
分頁模式的選擇主要由control register CR0,control register CR4,IA32_EFER MSR控制,
由上表可以看出:

  • CR0.PG = 0,關閉分頁單元,線性地址被直接解釋成物理地址;
  • CR0.PG = 1 && CR4.PAE = 0,使用32-bit分頁機制,線性地址大小是232,物理地址大小可以達到240,支持的頁大小是4KB和4MB;
  • CR0.PG = 1 && CR4.PAE = 1,使用PAE(Physical Address Extension)分頁機制,線性地址大小是232,物理地址大小可以達到252,支持的頁大小是4KB和2MB;
  • CR0.PG = 1 && CR4.PAE = 1 && IA32_EFER.LME = 1,使用4級分頁機制,線性地址大小是248,物理地址大小可以達到252,支持的頁大小是4KB、2MB和1GB;
  • CR0.PG = 1 && CR4.PAE = 1 && IA32_EFER.LME = 1 && CR4.LA57 = 1,使用5級分頁機制,線性地址大小是257,物理地址大小可以達到252,支持的頁大小是4KB、2MB和1GB;

2.1 32-bit Paging

暫存器狀態CR0.PG = 1 && CR4.PAE = 0 && IA32_EFER.LME = 0 時,X86選擇32-BIT PAGING分頁模式,
32-BIT PAGING分頁模式支持頁大小是4KB和4MB兩種,

以4KB大小頁為例,其分頁機制如下圖所示,
在這里插入圖片描述
32bit線性地址被劃分為3部分:

  1. Directory[31:22]:最高10bit;
  2. Table[21:12]:中間10bit;
  3. Offset[11:0]:最低12bit,

其原理與第一節所述原理如出一轍,頁表基址暫存器為CR3,用于索引一級頁表Page Directory(PDE),Page Directory用于索引二級頁表Page Table(PTE),Page Table和Offset共同找到Physical Address,

2.2 32-bit Paging頁表長啥樣?

如下圖所示是32-BIT PAGING分頁模式下,CR3暫存器和一級頁表PDE,二級頁表PTE的長相,
在這里插入圖片描述
CR3暫存器

  • Address of page directory[31:12]:線性地址轉換一級頁表物理地址,用于配合線性地址Page Directory找到一級頁表物理地址;
  • PCD[4]:Page-level cache disable
  • PWT[4]:Page-level write-through

PDE

  • Page size[7]:指定頁大小,為1則頁大小為4MB,為0則頁大小為4KB,頁大小不同則PDE的結構也不同,我們只看PS=0的情況,即4KB頁大小;
  • Present[0]:存在位,為1表示此頁在記憶體中,為0表示此頁不在記憶體中,地址轉換時,發現此位為0,則MMU將該地址放入CR2暫存器,并產生缺頁例外,
  • Read/write[1]:讀寫權限,為0表示該頁表只讀;
  • User/supervisor[2]:特權等級,為0則用戶模式無法訪問該頁表;
  • Page-level write-through[3]:控制Cache處理頁表方式,指定Cache直寫和回寫策略;
  • Page-level cache disable[4]:控制Cache處理頁表方式,指定Cache是否禁用;
  • Accessed[5]:訪問頁框時置位;
  • Address of page table[31:12]:線性地址轉換二級頁表物理地址,用于配合線性地址Page Table找到二級頁表物理地址;

PTE

  • [5:0]:與PDE一樣;
  • Dirty[6]:對頁框進行寫操作時置位;
  • Global[8]:CR4.PGE = 1時有效,防止常用頁從TLB中Flush掉,
  • Address of page table[31:12]:線性地址轉換物理地址,用于配合線性地址Offset找到物理地址;

其長相與第一節所述如出一轍,

2.3 4-Level Paging

再來看一個4級頁表分頁模式,支持的頁大小是4KB、2MB和1GB,
以4KB頁大小為例,如下圖所示,顯然相比于32-bit Paging,4-Level Paging擴展了線性地址(48bit)和物理地址(52bit),

隨著計算機的發展,32bit的地址空間顯很局促,尤其是物理尋址范圍也只有32bit,即4GB物理地址空間,在計算機發展初期4GB空間是天文數字,現在已經淪落到選擇個人PC都看不上4GB記憶體,起碼是8GB記憶體起步,這也是為什么X86 32位CPU支持PAE(Physical Address Extension)的原因,同樣的,ARM-v7也支持了LPAE(Large Physical Address Extension),名字雖不同,但困境如出一轍,

在這里插入圖片描述
4級頁表映射其原理與32bit Paging是一樣的,將47bit線性地址被劃分為5部分:

  1. PML4[47:39]:最高9bit;
  2. Directory Ptr[38:30]:中間9bit;
  3. Directory [29:21]:中間9bit;
  4. Table[20:12]:中間9bit;
  5. Offset[11:0]:最低12bit,

地址轉換程序也是一樣,從CR3開始逐級找到Physical Address,這里不再贅述了,

其原理真是如出一轍,

三、ARM中的分頁

看完了X86中的分頁,再看ARM中分頁,

3.1 ARMv7 Paging

ARMv7架構支持三種頁大小:1MB,64KB和4KB,同時ARMv7支持LPAE,可以將物理地址范圍擴大到40bit,
以4KB頁大小,未開啟LPAE為例,如下圖所示,
在這里插入圖片描述
32bit線性地址被劃分為3部分:

  1. L1 Table Index[31:20]:最高12bit;
  2. L2 Table Index[19:12]:中間8bit;
  3. Page Index[11:0]:最低12bit,

地址轉換程序,TTBR暫存器Translation base[31:14]和虛擬地址的L1 Table Index[31:20]索引到一級頁表物理地址,一級頁表Page table base address[31:10]和虛擬地址L2 Table Index[19:12]索引到二級頁表物理地址,二級頁表Small page base address[31:12]和虛擬地址的Page Index[11:0]索引到物理地址,

3.2 ARMv7 4KB Paging頁表長啥樣?

ARMv7 4KB分頁機制采用二級頁表管理,其一級頁表屬性如下圖所示,
在這里插入圖片描述

  • Page table base address[31:10]:線性地址轉換二級頁表物理地址,用于配合線性地址Page Table找到二級頁表物理地址;
  • NS[3]:Non-secure,非安全模式下忽略;
  • Domain[8:5]:域,記憶體區域的集合,可以定義16個域,劃分其訪問權限,超越域訪問權限時會觸發Permission fault,

二級頁表屬性如下圖所示,
在這里插入圖片描述

  • Small page base address[31:12]:線性地址轉換物理地址,用于配合線性地址offset找到物理地址;
  • XN[0]:Execute-never;
  • C,B[3:2]:定義內部cache屬性,
  • TEX[8:6]:定義外部cache屬性,
    在這里插入圖片描述
  • AP[9,5:4]:Access Permissions,當高位設定為1,則頁表為只讀權限;
     MMU access permissions
  • S[10]:Shareable;
  • nG[11]:not global,指定頁表是否是全域的,用于TLB;

3.3 ARMv8 分頁配置

ARMv8架構AArm64支持三種頁大小:64KB,16KB和4KB,
頁大小選擇由系統暫存器TCR控制,如下圖所示為TCR_EL1暫存器,
在這里插入圖片描述
比較重要的bit位說明:

  • T0SZ[5:0]:The size offset of the memory region addressed by TTBR0_EL1,TTBR0_EL1尋址的記憶體區域的大小偏移量,記憶體區域大小計算方法2(64-T0SZ);
  • T1SZ[21:16]:The size offset of the memory region addressed by TTBR1_EL1,TTBR1_EL1尋址的記憶體區域的大小偏移量,記憶體區域大小計算方法2(64-T0SZ);
  • IRGN0[9:8]/IRGN1[25:24]:Inner cacheability attribute for memory associated,控制內部Cache訪問模式,直寫和回寫;
  • ORGN0[11:10]/ORGN1[27:26]:Outer cacheability attribute for memory associated,控制外部Cache訪問模式,直寫和回寫;
  • TG0[15:14]:Granule size for the TTBR0_EL1,頁大小,為0表示4KB,1表示64KB,2表示16KB;
  • TG1[31:30]:Granule size for the TTBR1_EL1,頁大小,為0表示4KB,1表示64KB,3表示16KB;
  • A1[22]:ASID選擇,為0選擇TTBR0_EL1.ASID ,為1選擇TTBR1_EL1.ASID;
  • IPS[34:32]:Intermediate Physical Address Size,中間物理地址大小;
  • AS[36]:ASID Size,ASID大小,為0表示8bit,為1表示16bit;
  • HA[39]:Hardware Access flag update,Access使能位;
  • HD[40]:Hardware management of dirty state,Dirty使能位;

說明:

  • ARM架構提供了兩個頁表基址暫存器TTBR0和TTBR1,可以分別用于用戶態和內核態,
  • ASID用于標識行程,可以根據ASID劃分TLB entry,避免TLB entry頻繁Flush,

顯然系統暫存器TCR控制了頁表映射的引數,其中TCR.TG0/TG1決定了頁大小,

當頁大小為4KB時,分頁單元每級頁表的地址范圍如下,其中TnSZmin和TnSZmax分別表示TCR_ELx.TnSZ的最小最大值,IA表示Input Address,即虛擬地址:
在這里插入圖片描述

3.4 ARMv8 Paging

以頁大小為4KB,虛擬地址位寬為48bit為例,符合上一節中TCR_ELx.TnSZ為最小值的情況,如下圖所示,
在這里插入圖片描述
ARMv8對IA(input address)劃分成了五部分:

  1. Index the level 0 translation table[47:39]:最高9bit;
  2. Index the level 1 translation table[38:30]:中間9bit;
  3. Index the level 2 translation table [29:21]:中間9bit;
  4. Index the level 3 translation table[20:12]:中間9bit;
  5. OA[11:0]:output address,最低12bit,

這個劃分方法與X86 4-Level Paging一樣,
其地址轉換程序,與前述的地址轉換程序并無差別,從頁表基址暫存器TTBR_ELx開始逐級查找到物理地址,如下圖所示,
在這里插入圖片描述

四、Kernel中的分頁

Linux Kernel分頁為了支持不同的CPU體系架構,設計了五級分頁模型,如下圖所示,五級分頁模型是為了兼容X86-64體系架構中的5-Level Paging分頁模式,見第二節,
在這里插入圖片描述
五級分頁每級命名分別為頁全域目錄(PGD)、頁4級目錄(P4D)、頁上級目錄(PUD)、頁中間目錄(PMD)、頁表(PTE),對應的相關宏定義命名如下:

#define PGDIR_SHIFT
#define P4D_SHIFT
#define PUD_SHIFT
#define PMD_SHIFT
#define PAGE_SHIFT

這些宏定義與具體體系架構相關,如果體系架構只使用了4級,3級或者更少的分級映射,則將其中的某幾個定義忽略即可,

Linux對于頁表的操作主要定義了以下函式或宏,這些操作方法也是與體系架構相關的,因此需要按照體系架構的硬體定義去實作,

宏或函式說明
pgd_offset(mm, addr)根據入參記憶體描述符mm和虛擬地址address,找到address在頁全域目錄中相應表項的線性地址,
pgd_offset_k(addr)根據入參虛擬地址address和init_mm,找到address在頁全域目錄中相應表項的線性地址,僅用于內核頁表,
p4d_offset(pgd, addr)根據入參pgd和虛擬地址address,找到address在頁四級目錄中相應表項的線性地址,
pud_offset(p4d,addr)根據入參p4d和虛擬地址address,找到address在頁上級目錄中相應表項的線性地址,
pmd_offset(pud, address)根據入參pud和虛擬地址address,找到address在頁中間目錄中相應表項的線性地址,
pte_index(address)根據入參虛擬地址address,找到address在頁表中索引,
set_pgd(pgdp, pgd)向PGD寫入指定的值
set_p4d(p4dp, p4d)向P4D寫入指定的值
set_pud(pudp, pud)向PUD寫入指定的值
set_pmd(pmdp, pmd)向PMD寫入指定的值
set_pte(ptep, pte)向PTE寫入指定的值
pte_dirty(pte)讀Dirty標志
pte_mkdirty(pte)寫Dirty標志

分頁機制與CPU體系架構強相關,因此分析Linux Kernel分頁時還是需要根據體系架構分析,

4.1 X86分頁

X86架構中支持四種分頁模式:32-bit,PAE,4-Level Paging和5-Level Paging,對于ARM體系架構最多用到了4級分頁,而X86架構可以用到5級分頁,Linux對于X86分頁定義如下,

#ifdef CONFIG_X86_5LEVEL

/*
 * PGDIR_SHIFT determines what a top-level page table entry can map
 */
#define PGDIR_SHIFT	pgdir_shift
#define PTRS_PER_PGD	512

/*
 * 4th level page in 5-level paging case
 */
#define P4D_SHIFT		39
#define MAX_PTRS_PER_P4D	512
#define PTRS_PER_P4D		ptrs_per_p4d
#define P4D_SIZE		(_AC(1, UL) << P4D_SHIFT)
#define P4D_MASK		(~(P4D_SIZE - 1))

#define MAX_POSSIBLE_PHYSMEM_BITS	52

#else /* CONFIG_X86_5LEVEL */

/*
 * PGDIR_SHIFT determines what a top-level page table entry can map
 */
#define PGDIR_SHIFT		39
#define PTRS_PER_PGD		512
#define MAX_PTRS_PER_P4D	1

#endif /* CONFIG_X86_5LEVEL */

/*
 * 3rd level page
 */
#define PUD_SHIFT	30
#define PTRS_PER_PUD	512

/*
 * PMD_SHIFT determines the size of the area a middle-level
 * page table can map
 */
#define PMD_SHIFT	21
#define PTRS_PER_PMD	512

/*
 * entries per page directory level
 */
#define PTRS_PER_PTE	512

#define PMD_SIZE	(_AC(1, UL) << PMD_SHIFT)
#define PMD_MASK	(~(PMD_SIZE - 1))
#define PUD_SIZE	(_AC(1, UL) << PUD_SHIFT)
#define PUD_MASK	(~(PUD_SIZE - 1))
#define PGDIR_SIZE	(_AC(1, UL) << PGDIR_SHIFT)
#define PGDIR_MASK	(~(PGDIR_SIZE - 1))

我們以4級分頁為例,其對虛擬地址的劃分如下圖所示,在2.3節中已經說明,從Linux宏定義可以看出PGDIR_SHIFT對應PML4,值為39;PUD_SHIFT對應Directory Ptr,值為30;PMD_SHIFT對應Directory,值為21;使用4KB也大小時,PAGE_SIZE為4KB,即PAGE_SHIFT大小為12,對應Table,
PTRS_PER_PGD,PTRS_PER_PUD,PTRS_PER_PMD分別對應每級表項的個數,都是512個表項(2^9),
在這里插入圖片描述

4.1 ARMv7分頁

ARMv7作為32bit CPU架構,其分頁一般采用兩級分頁,第一級為頁目錄(PGD),第二級為頁映射表(PTE),頁大小為4KB,

如下圖所示為ARMv7頁表映射示意圖,與ARMv7硬體4KB分頁機制相對應,頁表基址暫存器TTBRx(x為0或1),
TTBRx(Translation Table Base Register x)即頁表轉換基址暫存器,ARMv7提供了TTBR0和TTBR1兩個暫存器,Linux分別將其應用于內核態和用戶態,行程地址空間切換實質就是將TTBR0暫存器中Translation Table Base 0 Address修改為當前行程的PGD(頁全域目錄),一級頁表數量為4096,二級頁表數量為256,

頁表映射程序是MMU通過TTBRx和虛擬地址VA[31:20]索引到PGD一級頁表,再由PGD一級頁表和虛擬地址VA[19:12]索引到PTE頁映射表,在由PTE頁映射表和虛擬地址VA[11:0]索引到物理地址,
在這里插入圖片描述
Linux對于上述PGD,PTE等資料的定義位于ARM體系架構目錄,如下所示:

/*
 * PMD_SHIFT determines the size of the area a second-level page table can map
 * PGDIR_SHIFT determines what a third-level page table entry can map
 */
#define PMD_SHIFT		21
#define PGDIR_SHIFT		21

#define PMD_SIZE		(1UL << PMD_SHIFT)
#define PMD_MASK		(~(PMD_SIZE-1))
#define PGDIR_SIZE		(1UL << PGDIR_SHIFT)
#define PGDIR_MASK		(~(PGDIR_SIZE-1))

這里會有一個疑惑,PMD和PGD沒有定義成20,和之前分析的不一致?

之前分析了ARMv7硬體分頁機制,4KB頁表大小進行分頁時,采用二級頁表結構,第一級有4096個表項,第二級有256個表項,二級頁表中的屬性沒有“dirty”位,
而Linux有一個三層的頁表結構,可以很容易地將其包裝成適合兩層的頁表結構—只使用PGD和PTE,但是,Linux還要求每個頁面有一個“PTE”表,而且至少要有一個“dirty”位,對于“dirty”位我們前面也講到了,“dirty”位在寫操作時被置位,表示頁面被寫過,頁面交換時會使用該標記,
因此,在這里稍微調整了實作—告訴Linux在第一級有2048個條目,每個都是8位元組,二級頁表包含兩個連續排列的硬體PTE表項,前面的表項是包含Linux需要的狀態資訊的Linux PTE,因此,最終在“PTE”級別上有512個表項,宏定義如下所示,

#define PTRS_PER_PTE		512
#define PTRS_PER_PMD		1
#define PTRS_PER_PGD		2048

#define PTE_HWTABLE_PTRS	(PTRS_PER_PTE)
#define PTE_HWTABLE_OFF		(PTE_HWTABLE_PTRS * sizeof(pte_t))
#define PTE_HWTABLE_SIZE	(PTRS_PER_PTE * sizeof(u32))

當頁面在Linux PTE中被標記為“可寫”和“dirty”時,“dirty”位通過授予硬體寫權限模擬,也就是說ARM頁表設定時將權限設定為只讀,當向頁面寫入時,會觸發缺頁例外(Linux PTE頁面表項標記了可寫權限,但是ARM硬體頁面表項是只讀權限),在缺頁例外處理函式handle_pte_fault()中會在該頁的Linux PTE頁面表項標記為“dirty”,為了讓硬體注意到權限的更改,必須重繪TLB條目,而ptep_set_access_flags()為我們完成了這項作業,

ARMv7頁表屬性的定義分為Linux版本的頁表和ARMv7硬體的頁表,
Linux版本的PTE頁表屬性定義加入前綴L_,如下所示:

/*
 * "Linux" PTE definitions.
 *
 * We keep two sets of PTEs - the hardware and the linux version.
 * This allows greater flexibility in the way we map the Linux bits
 * onto the hardware tables, and allows us to have YOUNG and DIRTY
 * bits.
 *
 * The PTE table pointer refers to the hardware entries; the "Linux"
 * entries are stored 1024 bytes below.
 */
#define L_PTE_VALID		(_AT(pteval_t, 1) << 0)		/* Valid */
#define L_PTE_PRESENT		(_AT(pteval_t, 1) << 0)
#define L_PTE_YOUNG		(_AT(pteval_t, 1) << 1)
#define L_PTE_DIRTY		(_AT(pteval_t, 1) << 6)
#define L_PTE_RDONLY		(_AT(pteval_t, 1) << 7)
#define L_PTE_USER		(_AT(pteval_t, 1) << 8)
#define L_PTE_XN		(_AT(pteval_t, 1) << 9)
#define L_PTE_SHARED		(_AT(pteval_t, 1) << 10)	/* shared(v6), coherent(xsc3) */
#define L_PTE_NONE		(_AT(pteval_t, 1) << 11)

ARMv7硬體的頁表屬性定義如下所示:

/*
 *   - extended small page/tiny page
 */
#define PTE_EXT_XN		(_AT(pteval_t, 1) << 0)		/* v6 */
#define PTE_EXT_AP_MASK		(_AT(pteval_t, 3) << 4)
#define PTE_EXT_AP0		(_AT(pteval_t, 1) << 4)
#define PTE_EXT_AP1		(_AT(pteval_t, 2) << 4)
#define PTE_EXT_AP_UNO_SRO	(_AT(pteval_t, 0) << 4)
#define PTE_EXT_AP_UNO_SRW	(PTE_EXT_AP0)
#define PTE_EXT_AP_URO_SRW	(PTE_EXT_AP1)
#define PTE_EXT_AP_URW_SRW	(PTE_EXT_AP1|PTE_EXT_AP0)
#define PTE_EXT_TEX(x)		(_AT(pteval_t, (x)) << 6)	/* v5 */
#define PTE_EXT_APX		(_AT(pteval_t, 1) << 9)		/* v6 */
#define PTE_EXT_COHERENT	(_AT(pteval_t, 1) << 9)		/* XScale3 */
#define PTE_EXT_SHARED		(_AT(pteval_t, 1) << 10)	/* v6 */
#define PTE_EXT_NG		(_AT(pteval_t, 1) << 11)	/* v6 */

ARMv7硬體的頁表屬性定義與3.2節中描述的硬體頁表的屬性是相互對應的,其含義與硬體頁表屬性含義一致,
通過對比Linux版本的頁表和ARMv7硬體的頁表會發現,ARMv7硬體的頁表缺少“dirty”位和“young”位,“dirty”位前邊已經講過,“young”位用于標志頁面剛剛被訪問過,在頁面換出時,如果頁面“young”位被標記,則不會將該頁換出,同時清除“young”位標記,“young”位的模擬方法與“dirty”位類似,也是利用了兩套PTE頁表模擬,一套用于Linux,一套用于ARM硬體,

ARMv7頁表如何下發到硬體?是通過set_pte_ext()函式實作的,

#define set_pte_ext(ptep,pte,ext) cpu_set_pte_ext(ptep,pte,ext)
#define cpu_set_pte_ext			PROC_TABLE(set_pte_ext)

不同CPU有不同的實作方式,以Cortex-A9為例,其實作是匯編函式cpu_v7_set_pte_ext:

/*
 *	cpu_v7_set_pte_ext(ptep, pte)
 *
 *	Set a level 2 translation table entry.
 *
 *	- ptep  - pointer to level 2 translation table entry
 *		  (hardware version is stored at +2048 bytes)
 *	- pte   - PTE value to store
 *	- ext	- value for extended PTE bits
 */
ENTRY(cpu_v7_set_pte_ext)
#ifdef CONFIG_MMU
	str	r1, [r0]			@ linux version @Linux PTE設定到r0指向的記憶體

	bic	r3, r1, #0x000003f0
	bic	r3, r3, #PTE_TYPE_MASK
	orr	r3, r3, r2
	orr	r3, r3, #PTE_EXT_AP0 | 2

	tst	r1, #1 << 4
	orrne	r3, r3, #PTE_EXT_TEX(1)

	eor	r1, r1, #L_PTE_DIRTY
	tst	r1, #L_PTE_RDONLY | L_PTE_DIRTY
	orrne	r3, r3, #PTE_EXT_APX @模擬“dirty”位,如果L_PTE_DIRTY置位,
	                             @則設定ARM硬體頁表APX位置位,設定頁表為只讀權限

	tst	r1, #L_PTE_USER
	orrne	r3, r3, #PTE_EXT_AP1

	tst	r1, #L_PTE_XN
	orrne	r3, r3, #PTE_EXT_XN

	tst	r1, #L_PTE_YOUNG
	tstne	r1, #L_PTE_VALID
	eorne	r1, r1, #L_PTE_NONE
	tstne	r1, #L_PTE_NONE
	moveq	r3, #0   @模擬“young”位,如果L_PTE_YONG清除且L_PTE_PRESENT置位,
	                 @則保持Linux版本頁表不變,ARM硬體頁表清除(r3置0即清空頁表)

 ARM(	str	r3, [r0, #2048]! ) @ARM PTE設定到r0+2048指向的記憶體
 THUMB(	add	r0, r0, #2048 )
 THUMB(	str	r3, [r0] )
	ALT_SMP(W(nop))
	ALT_UP (mcr	p15, 0, r0, c7, c10, 1)		@ flush_pte
#endif
	bx	lr
ENDPROC(cpu_v7_set_pte_ext)

暫存器r0是PTE表項指標,Linux使用的表項即r0所指記憶體,ARM硬體使用的表項地址是r0+2048,暫存器r1表示要寫入記憶體的Linux PTE表項的內容,其屬性bit位設定均使用L_前綴的宏定義,
第一句陳述句將Linux PTE設定到r0指向的記憶體,

str	r1, [r0]

str為記憶體操作指令,表示將資料從暫存器寫的記憶體,

如下陳述句將ARM PTE設定到r0+2048指向的記憶體,

ARM(	str	r3, [r0, #2048]! )

[r0, #2048]為前索引尋址模式,地址為暫存器R0中的值+立即數2048,偏移量為2048,計算出的新地址回寫到R0中,

關于記憶體操作指令詳細內容請看《ARM體系架構—ARMv7-A指令集:記憶體操作指令》

如下陳述句為ARMv7協處理器指令,指令含義為Data Cache Clean by MVA to PoC,即清除cache,

ALT_UP (mcr	p15, 0, r0, c7, c10, 1)	

CP15協處理器保護c0-c15共16個暫存器,暫存器32位的組織形式如下: C R n , o p c 1 , C R m , o p c 2 {CRn, opc1, CRm, opc2} CRn,opc1,CRm,opc2 對于匯編陳述句“mcr p15, 0, r0, c7, c10, 1”指示四個運算元結果如下:
在這里插入圖片描述

  • CRn:第一個協處理器暫存器c7;
  • opc1:協處理器操作碼0;
  • CRm:第二個協處理器暫存器c10;
  • opc2:協處理器操作碼1,

關于協處理指令詳細內容請看《ARM體系架構—ARMv7-A協處理器》

4.2 ARMv8分頁

ARMv8頁表支持三種粒度:4KB,16KB和64KB,
ARMv8支持48bit虛擬地址空間, 實作ARMv8.2-LVA( Large Virtual Address)并使用64KB頁大小時虛擬地址尋址空間可達52bit,當使用64KB頁大小時,ARMv8使用三級頁表;當使用4KB和16KB頁大小時,ARMv8使用四級頁表,正如下圖所示,
在這里插入圖片描述
ARMv8采用4KB頁大小,使用4級頁表時,記憶體分布如下,內核空間和用戶空間大小分別為256TB,內核空間地址范圍從0xffff000000000000到0xffffffffffffffff,共256TB空間,用戶空間地址范圍從0x0000000000000000到0x0000ffffffffffff,共256TB空間,

AArch64 Linux memory layout with 4KB pages + 4 levels (48-bit)::

  Start			End			Size		Use
  -----------------------------------------------------------------------
  0000000000000000	0000ffffffffffff	 256TB		user
  ffff000000000000	ffff7fffffffffff	 128TB		kernel logical memory map
  ffff800000000000	ffff9fffffffffff	  32TB		kasan shadow region
  ffffa00000000000	ffffa00007ffffff	 128MB		bpf jit region
  ffffa00008000000	ffffa0000fffffff	 128MB		modules
  ffffa00010000000	fffffdffbffeffff	 ~93TB		vmalloc
  fffffdffbfff0000	fffffdfffe5f8fff	~998MB		[guard region]
  fffffdfffe5f9000	fffffdfffe9fffff	4124KB		fixed mappings
  fffffdfffea00000	fffffdfffebfffff	   2MB		[guard region]
  fffffdfffec00000	fffffdffffbfffff	  16MB		PCI I/O space
  fffffdffffc00000	fffffdffffdfffff	   2MB		[guard region]
  fffffdffffe00000	ffffffffffdfffff	   2TB		vmemmap
  ffffffffffe00000	ffffffffffffffff	   2MB		[guard region]

ARM提供了兩個頁表基址暫存器TTBR0和TTBR1,在Linux中分別用于用戶空間和內核空間,內核空間地址高16位全為1,用戶空間地址高16位全為0,,如下圖所示,TTBR1和TTBR0分別管理0xffff000000000000到0xffffffffffffffff和0x0000000000000000到0x0000ffffffffffff兩部分地址空間,其余地址空間訪問則會發生例外,MMU做地址轉換時選擇TTBR1和TTBR0是根據虛擬地址VA[63],如果63bit為1則選擇TTBR1,為0則選擇TTBR0,
在這里插入圖片描述
ARMv8采用4KB頁大小,4級頁表映射,其虛擬地址劃分為,在3.4節中已經做過說明,
在這里插入圖片描述
Linux上述 Index the level 0 & 1 & 2 & 3 translation table等資料的定義位于ARM體系架構目錄,如下所示,

#define VA_BITS			(CONFIG_ARM64_VA_BITS)
#define ARM64_HW_PGTABLE_LEVEL_SHIFT(n)	((PAGE_SHIFT - 3) * (4 - (n)) + 3)

#define PTRS_PER_PTE		(1 << (PAGE_SHIFT - 3))

/*
 * PMD_SHIFT determines the size a level 2 page table entry can map.
 */
#if CONFIG_PGTABLE_LEVELS > 2
#define PMD_SHIFT		ARM64_HW_PGTABLE_LEVEL_SHIFT(2)
#define PMD_SIZE		(_AC(1, UL) << PMD_SHIFT)
#define PMD_MASK		(~(PMD_SIZE-1))
#define PTRS_PER_PMD		PTRS_PER_PTE
#endif

/*
 * PUD_SHIFT determines the size a level 1 page table entry can map.
 */
#if CONFIG_PGTABLE_LEVELS > 3
#define PUD_SHIFT		ARM64_HW_PGTABLE_LEVEL_SHIFT(1)
#define PUD_SIZE		(_AC(1, UL) << PUD_SHIFT)
#define PUD_MASK		(~(PUD_SIZE-1))
#define PTRS_PER_PUD		PTRS_PER_PTE
#endif

/*
 * PGDIR_SHIFT determines the size a top-level page table entry can map
 * (depending on the configuration, this level can be 0, 1 or 2).
 */
#define PGDIR_SHIFT		ARM64_HW_PGTABLE_LEVEL_SHIFT(4 - CONFIG_PGTABLE_LEVELS)
#define PGDIR_SIZE		(_AC(1, UL) << PGDIR_SHIFT)
#define PGDIR_MASK		(~(PGDIR_SIZE-1))
#define PTRS_PER_PGD		(1 << (VA_BITS - PGDIR_SHIFT))

PGDIR_SHIFT宏對應了 Index the level 0 translation table,當4KB頁大小,4級頁表映射時(PAGE_SHIFT = 12;CONFIG_PGTABLE_LEVELS = 4),通過計算可得PGDIR_SHIFT宏為39,與硬體分頁定義一致,

PGDIR_SHIFT	= (12-3)*(4-0)+3 = 39

CONFIG_PGTABLE_LEVELS表示使用頁表級數,當前使用的是4級頁表,所以CONFIG_PGTABLE_LEVELS>3,因此PUD定義為:

#define ARM64_HW_PGTABLE_LEVEL_SHIFT(n)	((PAGE_SHIFT - 3) * (4 - (n)) + 3)
#define PUD_SHIFT		ARM64_HW_PGTABLE_LEVEL_SHIFT(1)

PUD_SHIFT宏對應了 Index the level 1 translation table,帶入計算可知PUD_SHIFT為30,與硬體分頁定義一致,

PUD_SHIFT = (12-3)*(4-1)+3 = 30

CONFIG_PGTABLE_LEVELS表示使用頁表級數,當前使用的是4級頁表,所以CONFIG_PGTABLE_LEVELS>2,因此PMD定義為:

#define ARM64_HW_PGTABLE_LEVEL_SHIFT(n)	((PAGE_SHIFT - 3) * (4 - (n)) + 3)
#define PMD_SHIFT		ARM64_HW_PGTABLE_LEVEL_SHIFT(2)

PMD_SHIFT宏對應了 Index the level 3 translation table,帶入計算可知PUD_SHIFT為21,與硬體分頁定義一致,

PMD_SHIFT = (12-3)*(4-2)+3 = 21

至此,PGD,PUD,PMD都已獲悉,對應的其他宏的值也可以順利計算出結果,

#define PGDIR_SIZE		512GB
#define PTRS_PER_PGD	512

#define PUD_SIZE		1GB
#define PTRS_PER_PUD	512

#define PMD_SIZE		2MB
#define PTRS_PER_PMD	512

ARMv8 Linux下發PGD,PUD,PMD,PTE并沒有使用匯編語言,而是使用C語言實作,對應的函式如下,其實作原理都是將對應的表項內容寫入表項所在地址,

/* 向記憶體下發PGD頁表,入參分別為pgd頁表虛擬地址和pgd表項*/
static inline void set_pgd(pgd_t *pgdp, pgd_t pgd)
{
	if (in_swapper_pgdir(pgdp)) {
		set_swapper_pgd(pgdp, pgd);  /* 將pgd寫入swapper_pg_dir所指地址 */
		return;
	}

	WRITE_ONCE(*pgdp, pgd); /* 將pgd寫入pgdp所指地址 */
	dsb(ishst); /* 資料記憶體屏障 */
	isb(); /* 指令記憶體屏障 */
}

static inline void set_pud(pud_t *pudp, pud_t pud)
{
#ifdef __PAGETABLE_PUD_FOLDED
	if (in_swapper_pgdir(pudp)) {
		set_swapper_pgd((pgd_t *)pudp, __pgd(pud_val(pud)));
		return;
	}
#endif /* __PAGETABLE_PUD_FOLDED */

	WRITE_ONCE(*pudp, pud); /* 將pud寫入pudp所指地址 */

	if (pud_valid(pud)) {
		dsb(ishst);
		isb();
	}
}

static inline void set_pmd(pmd_t *pmdp, pmd_t pmd)
{
#ifdef __PAGETABLE_PMD_FOLDED
	if (in_swapper_pgdir(pmdp)) {
		set_swapper_pgd((pgd_t *)pmdp, __pgd(pmd_val(pmd)));
		return;
	}
#endif /* __PAGETABLE_PMD_FOLDED */

	WRITE_ONCE(*pmdp, pmd); /* 將pmd寫入pmdp所指地址 */

	if (pmd_valid(pmd)) {
		dsb(ishst);
		isb();
	}
}

static inline void set_pte(pte_t *ptep, pte_t pte)
{
	WRITE_ONCE(*ptep, pte); /* 將pte寫入ptep所指地址 */

	/*
	 * Only if the new pte is valid and kernel, otherwise TLB maintenance
	 * or update_mmu_cache() have the necessary barriers.
	 */
	if (pte_valid_not_user(pte)) {
		dsb(ishst);
		isb();
	}
}

本文內核版本為Linux5.6.4,

轉載請註明出處,本文鏈接:https://www.uj5u.com/qita/171744.html

標籤:其他

上一篇:linux arm32 mmu 啟動代碼分析(匯編部分)

下一篇:SQL 常用資料型別匯總

標籤雲
其他(157675) Python(38076) JavaScript(25376) Java(17977) C(15215) 區塊鏈(8255) C#(7972) AI(7469) 爪哇(7425) MySQL(7132) html(6777) 基礎類(6313) sql(6102) 熊猫(6058) PHP(5869) 数组(5741) R(5409) Linux(5327) 反应(5209) 腳本語言(PerlPython)(5129) 非技術區(4971) Android(4554) 数据框(4311) css(4259) 节点.js(4032) C語言(3288) json(3245) 列表(3129) 扑(3119) C++語言(3117) 安卓(2998) 打字稿(2995) VBA(2789) Java相關(2746) 疑難問題(2699) 细绳(2522) 單片機工控(2479) iOS(2429) ASP.NET(2402) MongoDB(2323) 麻木的(2285) 正则表达式(2254) 字典(2211) 循环(2198) 迅速(2185) 擅长(2169) 镖(2155) 功能(1967) .NET技术(1958) Web開發(1951) python-3.x(1918) HtmlCss(1915) 弹簧靴(1913) C++(1909) xml(1889) PostgreSQL(1872) .NETCore(1853) 谷歌表格(1846) Unity3D(1843) for循环(1842)

熱門瀏覽
  • 網閘典型架構簡述

    網閘架構一般分為兩種:三主機的三系統架構網閘和雙主機的2+1架構網閘。 三主機架構分別為內端機、外端機和仲裁機。三機無論從軟體和硬體上均各自獨立。首先從硬體上來看,三機都用各自獨立的主板、記憶體及存盤設備。從軟體上來看,三機有各自獨立的作業系統。這樣能達到完全的三機獨立。對于“2+1”系統,“2”分為 ......

    uj5u.com 2020-09-10 02:00:44 more
  • 如何從xshell上傳檔案到centos linux虛擬機里

    如何從xshell上傳檔案到centos linux虛擬機里及:虛擬機CentOs下執行 yum -y install lrzsz命令,出現錯誤:鏡像無法找到軟體包 前言 一、安裝lrzsz步驟 二、上傳檔案 三、遇到的問題及解決方案 總結 前言 提示:其實很簡單,往虛擬機上安裝一個上傳檔案的工具 ......

    uj5u.com 2020-09-10 02:00:47 more
  • 一、SQLMAP入門

    一、SQLMAP入門 1、判斷是否存在注入 sqlmap.py -u 網址/id=1 id=1不可缺少。當注入點后面的引數大于兩個時。需要加雙引號, sqlmap.py -u "網址/id=1&uid=1" 2、判斷文本中的請求是否存在注入 從文本中加載http請求,SQLMAP可以從一個文本檔案中 ......

    uj5u.com 2020-09-10 02:00:50 more
  • Metasploit 簡單使用教程

    metasploit 簡單使用教程 浩先生, 2020-08-28 16:18:25 分類專欄: kail 網路安全 linux 文章標簽: linux資訊安全 編輯 著作權 metasploit 使用教程 前言 一、Metasploit是什么? 二、準備作業 三、具體步驟 前言 Msfconsole ......

    uj5u.com 2020-09-10 02:00:53 more
  • 游戲逆向之驅動層與用戶層通訊

    驅動層代碼: #pragma once #include <ntifs.h> #define add_code CTL_CODE(FILE_DEVICE_UNKNOWN,0x800,METHOD_BUFFERED,FILE_ANY_ACCESS) /* 更多游戲逆向視頻www.yxfzedu.com ......

    uj5u.com 2020-09-10 02:00:56 more
  • 北斗電力時鐘(北斗授時服務器)讓網路資料更精準

    北斗電力時鐘(北斗授時服務器)讓網路資料更精準 北斗電力時鐘(北斗授時服務器)讓網路資料更精準 京準電子科技官微——ahjzsz 近幾年,資訊技術的得了快速發展,互聯網在逐漸普及,其在人們生活和生產中都得到了廣泛應用,并且取得了不錯的應用效果。計算機網路資訊在電力系統中的應用,一方面使電力系統的運行 ......

    uj5u.com 2020-09-10 02:01:03 more
  • 【CTF】CTFHub 技能樹 彩蛋 writeup

    ?碎碎念 CTFHub:https://www.ctfhub.com/ 筆者入門CTF時時剛開始刷的是bugku的舊平臺,后來才有了CTFHub。 感覺不論是網頁UI設計,還是題目質量,賽事跟蹤,工具軟體都做得很不錯。 而且因為獨到的金幣制度的確讓人有一種想去刷題賺金幣的感覺。 個人還是非常喜歡這個 ......

    uj5u.com 2020-09-10 02:04:05 more
  • 02windows基礎操作

    我學到了一下幾點 Windows系統目錄結構與滲透的作用 常見Windows的服務詳解 Windows埠詳解 常用的Windows注冊表詳解 hacker DOS命令詳解(net user / type /md /rd/ dir /cd /net use copy、批處理 等) 利用dos命令制作 ......

    uj5u.com 2020-09-10 02:04:18 more
  • 03.Linux基礎操作

    我學到了以下幾點 01Linux系統介紹02系統安裝,密碼啊破解03Linux常用命令04LAMP 01LINUX windows: win03 8 12 16 19 配置不繁瑣 Linux:redhat,centos(紅帽社區版),Ubuntu server,suse unix:金融機構,證券,銀 ......

    uj5u.com 2020-09-10 02:04:30 more
  • 05HTML

    01HTML介紹 02頭部標簽講解03基礎標簽講解04表單標簽講解 HTML前段語言 js1.了解代碼2.根據代碼 懂得挖掘漏洞 (POST注入/XSS漏洞上傳)3.黑帽seo 白帽seo 客戶網站被黑帽植入劫持代碼如何處理4.熟悉html表單 <html><head><title>TDK標題,描述 ......

    uj5u.com 2020-09-10 02:04:36 more
最新发布
  • 2023年最新微信小程式抓包教程

    01 開門見山 隔一個月發一篇文章,不過分。 首先回顧一下《微信系結手機號資料庫被脫庫事件》,我也是第一時間得知了這個訊息,然后跟蹤了整件事情的經過。下面是這起事件的相關截圖以及近日流出的一萬條資料樣本: 個人認為這件事也沒什么,還不如關注一下之前45億快遞資料查詢渠道疑似在近日復活的訊息。 訊息是 ......

    uj5u.com 2023-04-20 08:48:24 more
  • web3 產品介紹:metamask 錢包 使用最多的瀏覽器插件錢包

    Metamask錢包是一種基于區塊鏈技術的數字貨幣錢包,它允許用戶在安全、便捷的環境下管理自己的加密資產。Metamask錢包是以太坊生態系統中最流行的錢包之一,它具有易于使用、安全性高和功能強大等優點。 本文將詳細介紹Metamask錢包的功能和使用方法。 一、 Metamask錢包的功能 數字資 ......

    uj5u.com 2023-04-20 08:47:46 more
  • vulnhub_Earth

    前言 靶機地址->>>vulnhub_Earth 攻擊機ip:192.168.20.121 靶機ip:192.168.20.122 參考文章 https://www.cnblogs.com/Jing-X/archive/2022/04/03/16097695.html https://www.cnb ......

    uj5u.com 2023-04-20 07:46:20 more
  • 從4k到42k,軟體測驗工程師的漲薪史,給我看哭了

    清明節一過,盲猜大家已經無心上班,在數著日子準備過五一,但一想到銀行卡里的余額……瞬間心情就不美麗了。最近,2023年高校畢業生就業調查顯示,本科畢業月平均起薪為5825元。調查一出,便有很多同學表示自己又被平均了。看著這一資料,不免讓人想到前不久中國青年報的一項調查:近六成大學生認為畢業10年內會 ......

    uj5u.com 2023-04-20 07:44:00 more
  • 最新版本 Stable Diffusion 開源 AI 繪畫工具之中文自動提詞篇

    🎈 標簽生成器 由于輸入正向提示詞 prompt 和反向提示詞 negative prompt 都是使用英文,所以對學習母語的我們非常不友好 使用網址:https://tinygeeker.github.io/p/ai-prompt-generator 這個網址是為了讓大家在使用 AI 繪畫的時候 ......

    uj5u.com 2023-04-20 07:43:36 more
  • 漫談前端自動化測驗演進之路及測驗工具分析

    隨著前端技術的不斷發展和應用程式的日益復雜,前端自動化測驗也在不斷演進。隨著 Web 應用程式變得越來越復雜,自動化測驗的需求也越來越高。如今,自動化測驗已經成為 Web 應用程式開發程序中不可或缺的一部分,它們可以幫助開發人員更快地發現和修復錯誤,提高應用程式的性能和可靠性。 ......

    uj5u.com 2023-04-20 07:43:16 more
  • CANN開發實踐:4個DVPP記憶體問題的典型案例解讀

    摘要:由于DVPP媒體資料處理功能對存放輸入、輸出資料的記憶體有更高的要求(例如,記憶體首地址128位元組對齊),因此需呼叫專用的記憶體申請介面,那么本期就分享幾個關于DVPP記憶體問題的典型案例,并給出原因分析及解決方法。 本文分享自華為云社區《FAQ_DVPP記憶體問題案例》,作者:昇騰CANN。 DVPP ......

    uj5u.com 2023-04-20 07:43:03 more
  • msf學習

    msf學習 以kali自帶的msf為例 一、msf核心模塊與功能 msf模塊都放在/usr/share/metasploit-framework/modules目錄下 1、auxiliary 輔助模塊,輔助滲透(埠掃描、登錄密碼爆破、漏洞驗證等) 2、encoders 編碼器模塊,主要包含各種編碼 ......

    uj5u.com 2023-04-20 07:42:59 more
  • Halcon軟體安裝與界面簡介

    1. 下載Halcon17版本到到本地 2. 雙擊安裝包后 3. 步驟如下 1.2 Halcon軟體安裝 界面分為四大塊 1. Halcon的五個助手 1) 影像采集助手:與相機連接,設定相機引數,采集影像 2) 標定助手:九點標定或是其它的標定,生成標定檔案及內參外參,可以將像素單位轉換為長度單位 ......

    uj5u.com 2023-04-20 07:42:17 more
  • 在MacOS下使用Unity3D開發游戲

    第一次發博客,先發一下我的游戲開發環境吧。 去年2月份買了一臺MacBookPro2021 M1pro(以下簡稱mbp),這一年來一直在用mbp開發游戲。我大致分享一下我的開發工具以及使用體驗。 1、Unity 官網鏈接: https://unity.cn/releases 我一般使用的Apple ......

    uj5u.com 2023-04-20 07:40:19 more