一、ARM64 架構地址空間的「黃金分割」
ARM64(ARMv8-A)采用?48 位虛擬地址(Linux 默認配置),總空間為?256TB,分為高低兩個 128TB 區域:
1.?地址空間整體布局
虛擬地址空間(48位,256TB)
┌───────────────────────────────────────┐
│ 用戶空間(低128TB) │
│ 0x000000000000 ~ 0x000FFFFFFFFF │ (低地址段,用戶進程使用)
├───────────────────────────────────────┤
│ 保留隔離區 │
│ 0x010000000000 ~ 0xFFFFEFFFFFFFFFFF │ (未使用,防止地址越界)
├───────────────────────────────────────┤
│ 內核空間(高128TB) │
│ 0xFFFF00000000 ~ 0xFFFFFFFFFFFFFFFF │ (高地址段,內核專屬空間)
└───────────────────────────────────────┘
2.?核心劃分依據
- 分界線:
0xFFFF00000000
(由內核配置CONFIG_ARM64_PAGE_OFFSET
決定) - 用戶空間:低 128TB,地址最高位為?
0b00...
(前 16 位為 0) - 內核空間:高 128TB,地址最高位為?
0b111111...
(前 16 位為全 1)
二、圖形化對比:用戶空間 vs 內核空間?
1.?地址范圍與用途對比圖?
虛擬地址空間(ARM64, 48位)
低地址───────────────────────────────────────高地址
┌───────────────────────────────────────┐
│ 用戶空間(128TB) │
│ ╔══════════════════════════════════╗ │
│ ║ 進程A的代碼/數據/堆/棧 ║ │
│ ║ 進程B的代碼/數據/堆/棧 ║ │
│ ║ ... ║ │
│ ╚══════════════════════════════════╝ │
│ │
├───────────────────────────────────────┤
│ 內核空間(128TB) │
│ ╔══════════════════════════════════╗ │
│ ║ 內核代碼(.text/.data) ║ │
│ ║ 物理內存映射(memmap) ║ │
│ ║ 設備寄存器映射(ioremap) ║ │
│ ║ 動態分配內存(vmalloc) ║ │
│ ║ 全局內核數據(如task_struct) ║ │
│ ╚══════════════════════════════════╝ │
└───────────────────────────────────────┘
2.?關鍵差異點對比表
特征 | 用戶空間地址 | 內核空間地址 |
---|---|---|
地址范圍 | 0x000000000000 ~ 0x000FFFFFFFFF | 0xFFFF00000000 ~ 0xFFFFFFFFFFFFFFFF |
最高位標志 | 前 16 位為0b00... (低地址段) | 前 16 位為0b111111... (高地址段) |
訪問權限 | 用戶態受限(僅本進程可訪問) | 內核態全權限(所有進程共享) |
頁表機制 | 每個進程獨立頁表(地址隔離) | 全局頁表(所有進程共享同一映射) |
特權標志 | 頁表項設置PXN=1 (用戶態禁止執行) | 頁表項設置PXN=0 (內核態允許執行) |
典型場景 | 存儲用戶程序、堆、棧、動態庫 | 存儲內核代碼、設備驅動、物理內存映射 |
三、技術實現:ARM64 如何隔離兩個空間?
1.?頁表項中的「權限開關」
ARM64 通過?頁表項(PTE)標志位?控制訪問權限,核心標志:
PXN
(Permission Execute Never):- 用戶空間頁表項:
PXN=1
?→ 用戶態下禁止執行該頁的代碼(防惡意代碼注入)。 - 內核空間頁表項:
PXN=0
?→ 內核態下允許執行(如內核函數調用)。
- 用戶空間頁表項:
UXN
(User Execute Never):- 用戶空間數據頁:
UXN=1
?→ 用戶態下禁止執行數據頁(防棧溢出攻擊)。
- 用戶空間數據頁:
graph TD
A[用戶態程序訪問地址] --> B{地址 < 0xFFFF00000000 ?}
B -->|是| C[查詢用戶進程頁表]
C --> D{頁表項PXN=1 ?}
D -->|是| E[允許訪問(用戶空間數據/代碼)]
D -->|否| F[觸發頁錯誤(用戶態禁止執行)]
B -->|否| G[觸發頁錯誤(用戶態禁止訪問內核空間)]H[內核態程序訪問地址] --> I{地址 >= 0xFFFF00000000 ?}
I -->|是| J[查詢全局內核頁表]
J --> K[允許訪問(內核態無PXN限制)]
I -->|否| L[查詢用戶進程頁表(需通過copy_from_user)]
3.?實戰代碼:判斷地址所屬空間
// ARM64內核空間起始地址(Linux默認)
#define KERNEL_SPACE_START 0xFFFF00000000ULLbool is_kernel_address(unsigned long addr) {// 檢查地址是否位于高128TB(內核空間)return (addr & 0xFF0000000000ULL) == 0xFF0000000000ULL;
}// 示例:
unsigned long user_addr = 0x12345678ABCDULL; // 低地址,用戶空間
unsigned long kernel_addr = 0xFFFF12345678ABCDULL; // 高地址,內核空間printf("user_addr屬于%s空間\n", is_kernel_address(user_addr) ? "內核" : "用戶");
// 輸出:user_addr屬于用戶空間
四、64 位 vs 32 位 ARM 地址空間對比?
特征 | ARM64(48 位) | ARM32(32 位,3:1 劃分) |
---|---|---|
總空間 | 256TB | 4GB |
用戶空間 | 低 128TB(0x000... ~ 0x00F...) | 低 3GB(0x00000000 ~ 0xBFFFFFFF) |
內核空間 | 高 128TB(0xFFF... ~ 0xFFFF...) | 高 1GB(0xC0000000 ~ 0xFFFFFFFF) |
地址標志 | 最高 16 位全 1(內核)/ 全 0(用戶) | 最高 2 位為 11(內核,如 0xC0000000) |
隔離方式 | 物理地址標簽 + PXN/UXN 硬件保護 | 軟件頁表權限 + PAGE_OFFSET 劃分 |
五、典型場景:進程切換時的地址空間變化?
當用戶態進程通過?syscall
?進入內核時:
- 地址切換:
- 用戶態棧地址(如
0x0000...
)→ 內核態棧地址(如0xFFFF...
)。
- 用戶態棧地址(如
- 權限升級:
- CPU 從?EL0(用戶態)?切換到?EL1(內核態),解除 PXN/UXN 限制。
- 頁表共享:
- 用戶空間頁表繼續使用,但內核空間通過全局頁表訪問高地址段。
總結:3 步快速區分 ARM64 地址空間
- 看最高位:前 16 位是否為?
0b111111...
(內核空間)或?0b00...
(用戶空間)。 - 查訪問權限:用戶態程序能否直接訪問(能→用戶空間,否則→內核空間)。
- 看上下文:代碼是否運行在內核態(如中斷處理、系統調用),若是則為內核空間地址。
通過這種「地址范圍 + 硬件權限 + 執行環境」的三重判斷,就能準確區分 ARM64 架構下的用戶空間與內核空間地址。