啟動時記憶體管理¶
早期系統初始化無法使用“普通”記憶體管理,因為它尚未設定。但仍需要為各種資料結構分配記憶體,例如物理頁分配器。
一個名為 memblock 的專用分配器執行啟動時記憶體管理。特定架構的初始化必須在 setup_arch() 函式中設定它,並在 mem_init() 函式中將其拆除。
一旦早期記憶體管理可用,它會提供各種函式和宏用於記憶體分配。分配請求可以定向到第一個(也可能是唯一)節點,或者 NUMA 系統中的特定節點。存在在分配失敗時導致恐慌的 API 變體,也有不會恐慌的。
Memblock 還提供了多種控制其自身行為的 API。
Memblock 概述¶
Memblock 是一種在早期啟動期間管理記憶體區域的方法,此時常規的核心記憶體分配器尚未啟動和執行。
Memblock 將系統記憶體視為連續區域的集合。這些集合有幾種型別:
memory- 描述核心可用的物理記憶體;這可能與系統中實際安裝的物理記憶體不同,例如當記憶體受mem=命令列引數限制時reserved- 描述已分配的區域physmem- 描述啟動期間可用的實際物理記憶體,無論可能存在的限制和記憶體熱插拔/熱拔;physmem型別僅在某些架構上可用。
每個區域由 struct memblock_region 表示,該結構定義了區域的範圍、其屬性以及 NUMA 系統上的 NUMA 節點 ID。每種記憶體型別由 struct memblock_type 描述,該結構包含一個記憶體區域陣列以及分配器元資料。“memory”和“reserved”型別被很好地封裝在 struct memblock 中。該結構在構建時靜態初始化。區域陣列的初始大小,“memory”型別為 INIT_MEMBLOCK_MEMORY_REGIONS,“reserved”型別為 INIT_MEMBLOCK_RESERVED_REGIONS。“physmem”型別的區域陣列初始大小為 INIT_PHYSMEM_REGIONS。memblock_allow_resize() 在新增新區域時啟用區域陣列的自動調整大小。應謹慎使用此功能,以確保為區域陣列分配的記憶體不會與應保留的區域(例如 initrd)重疊。
早期架構設定應使用 memblock_add() 或 memblock_add_node() 函式告知 memblock 物理記憶體佈局。第一個函式不將區域分配給 NUMA 節點,適用於 UMA 系統。然而,它也可以在 NUMA 系統上使用,並在後續設定過程中使用 memblock_set_node() 將區域分配給 NUMA 節點。memblock_add_node() 直接執行此類分配。
一旦 memblock 設定完畢,就可以使用以下 API 變體之一分配記憶體:
memblock_phys_alloc*() - 這些函式返回已分配記憶體的物理地址
memblock_alloc*() - 這些函式返回已分配記憶體的虛擬地址。
請注意,這兩種 API 變體都隱含地假設了允許的記憶體範圍和回退方法。有關更詳細的描述,請查閱 memblock_alloc_internal() 和 memblock_alloc_range_nid() 函式的文件。
隨著系統啟動的進行,特定架構的 mem_init() 函式會將所有記憶體釋放給夥伴頁分配器。
除非某個架構啟用 CONFIG_ARCH_KEEP_MEMBLOCK,否則 memblock 資料結構(“physmem”除外)將在系統初始化完成後被丟棄。
函式和結構體¶
以下是 memblock 資料結構、函式和宏的描述。其中一些實際上是內部的,但既然它們有文件,省略它們會很愚蠢。此外,閱讀內部函式的描述有助於理解其底層實際發生的情況。
-
enum memblock_flags¶
記憶體區域屬性定義
常量
MEMBLOCK_NONE無特殊要求
MEMBLOCK_HOTPLUG韌體在早期啟動期間提供的記憶體對映中指示的、可熱插拔(可熱拔插)的系統 RAM 記憶體區域(例如,以後可能被熱拔插的記憶體範圍)。如果在核心命令列中設定了“movable_node”,則嘗試保持此記憶體區域可熱拔插。不適用於早期啟動後新增(“熱插拔”)的 memblock。
MEMBLOCK_MIRROR映象區域
MEMBLOCK_NOMAP不新增到核心直接對映中,並在記憶體對映中視為保留;有關詳細資訊,請參閱
memblock_mark_nomap()的描述MEMBLOCK_DRIVER_MANAGED始終透過驅動檢測並新增的記憶體區域,且從未在韌體提供的記憶體對映中指示為系統 RAM。這與核心資源樹中的 IORESOURCE_SYSRAM_DRIVER_MANAGED 相對應。
MEMBLOCK_RSRV_NOINITstruct pages 未初始化的記憶體區域(僅適用於保留區域)。
MEMBLOCK_RSRV_KERN為核心使用而保留的記憶體區域,可以透過 memblock_reserve_kern() 或透過 memblock 分配 API 顯式保留。所有 memblock 分配都會設定此標誌。
MEMBLOCK_KHO_SCRATCHkexec 在移交模式下可以傳遞給下一個核心的記憶體區域。在早期啟動期間,我們尚不瞭解所有記憶體保留,因此我們從前一個核心中獲取我們知道可以使用的臨時記憶體。這是在此階段唯一可以進行分配的記憶體。
-
struct memblock_region¶
表示一個記憶體區域
定義:
struct memblock_region {
phys_addr_t base;
phys_addr_t size;
enum memblock_flags flags;
#ifdef CONFIG_NUMA;
int nid;
#endif;
};
成員
base區域的基地址
size區域的大小
flags記憶體區域屬性
nidNUMA 節點 ID
-
struct memblock_type¶
某種型別的記憶體區域集合
定義:
struct memblock_type {
unsigned long cnt;
unsigned long max;
phys_addr_t total_size;
struct memblock_region *regions;
char *name;
};
成員
cnt區域數量
max已分配陣列的大小
total_size所有區域的總大小
regions區域陣列
name記憶體型別的符號名稱
-
struct memblock¶
memblock 分配器元資料
定義:
struct memblock {
bool bottom_up;
phys_addr_t current_limit;
struct memblock_type memory;
struct memblock_type reserved;
};
成員
bottom_up是自下而上方向嗎?
current_limit當前分配限制的物理地址
memory可用記憶體區域
reserved保留記憶體區域
-
for_each_physmem_range¶
for_each_physmem_range (i, type, p_start, p_end)
遍歷不包含在 type 中的 physmem 區域。
引數
i用作迴圈變數的 u64
type指向 memblock_type 的指標,該型別從迭代中排除,可以是
NULLp_start指向 phys_addr_t 的指標,用於範圍的起始地址,可以是
NULLp_end指向 phys_addr_t 的指標,用於範圍的結束地址,可以是
NULL
-
__for_each_mem_range¶
__for_each_mem_range (i, type_a, type_b, nid, flags, p_start, p_end, p_nid)
遍歷 type_a 中的 memblock 區域,且不包含在 type_b 中。如果 type_b 為 NULL,則僅遍歷 type_a。
引數
i用作迴圈變數的 u64
type_a指向要迭代的 memblock_type 的指標
type_b指向 memblock_type 的指標,該型別從迭代中排除
nid節點選擇器,
NUMA_NO_NODE表示所有節點flags根據記憶體屬性從塊中選擇
p_start指向 phys_addr_t 的指標,用於範圍的起始地址,可以是
NULLp_end指向 phys_addr_t 的指標,用於範圍的結束地址,可以是
NULLp_nid指向 int 的指標,用於範圍的 nid,可以是
NULL
-
__for_each_mem_range_rev¶
__for_each_mem_range_rev (i, type_a, type_b, nid, flags, p_start, p_end, p_nid)
反向遍歷 type_a 中的 memblock 區域,且不包含在 type_b 中。如果 type_b 為 NULL,則僅反向遍歷 type_a。
引數
i用作迴圈變數的 u64
type_a指向要迭代的 memblock_type 的指標
type_b指向 memblock_type 的指標,該型別從迭代中排除
nid節點選擇器,
NUMA_NO_NODE表示所有節點flags根據記憶體屬性從塊中選擇
p_start指向 phys_addr_t 的指標,用於範圍的起始地址,可以是
NULLp_end指向 phys_addr_t 的指標,用於範圍的結束地址,可以是
NULLp_nid指向 int 的指標,用於範圍的 nid,可以是
NULL
-
for_each_mem_range¶
for_each_mem_range (i, p_start, p_end)
遍歷記憶體區域。
引數
i用作迴圈變數的 u64
p_start指向 phys_addr_t 的指標,用於範圍的起始地址,可以是
NULLp_end指向 phys_addr_t 的指標,用於範圍的結束地址,可以是
NULL
-
for_each_mem_range_rev¶
for_each_mem_range_rev (i, p_start, p_end)
反向遍歷 type_a 中的 memblock 區域,且不包含在 type_b 中。如果 type_b 為 NULL,則僅反向遍歷 type_a。
引數
i用作迴圈變數的 u64
p_start指向 phys_addr_t 的指標,用於範圍的起始地址,可以是
NULLp_end指向 phys_addr_t 的指標,用於範圍的結束地址,可以是
NULL
-
for_each_reserved_mem_range¶
for_each_reserved_mem_range (i, p_start, p_end)
遍歷所有保留的 memblock 區域
引數
i用作迴圈變數的 u64
p_start指向 phys_addr_t 的指標,用於範圍的起始地址,可以是
NULLp_end指向 phys_addr_t 的指標,用於範圍的結束地址,可以是
NULL
描述
遍歷 memblock 的保留區域。Memblock 初始化後即可使用。
-
for_each_mem_pfn_range¶
for_each_mem_pfn_range (i, nid, p_start, p_end, p_nid)
早期記憶體 pfn 範圍迭代器
引數
i用作迴圈變數的整數
nid節點選擇器,
MAX_NUMNODES表示所有節點p_start指向 ulong 的指標,用於範圍的起始 pfn,可以是
NULLp_end指向 ulong 的指標,用於範圍的結束 pfn,可以是
NULLp_nid指向 int 的指標,用於範圍的 nid,可以是
NULL
描述
遍歷已配置的記憶體範圍。
-
for_each_free_mem_pfn_range_in_zone_from¶
for_each_free_mem_pfn_range_in_zone_from (i, zone, p_start, p_end)
從給定點開始遍歷特定區域的空閒 memblock 區域
引數
i用作迴圈變數的 u64
zone所有記憶體塊所在的區域
p_start指向 phys_addr_t 的指標,用於範圍的起始地址,可以是
NULLp_end指向 phys_addr_t 的指標,用於範圍的結束地址,可以是
NULL
描述
遍歷特定區域中空閒的(memory && !reserved)memblock 區域,從當前位置繼續。Memblock 初始化後即可使用。
-
for_each_free_mem_range¶
for_each_free_mem_range (i, nid, flags, p_start, p_end, p_nid)
遍歷空閒的 memblock 區域
引數
i用作迴圈變數的 u64
nid節點選擇器,
NUMA_NO_NODE表示所有節點flags根據記憶體屬性從塊中選擇
p_start指向 phys_addr_t 的指標,用於範圍的起始地址,可以是
NULLp_end指向 phys_addr_t 的指標,用於範圍的結束地址,可以是
NULLp_nid指向 int 的指標,用於範圍的 nid,可以是
NULL
描述
遍歷 memblock 中空閒的(memory && !reserved)區域。Memblock 初始化後即可使用。
-
for_each_free_mem_range_reverse¶
for_each_free_mem_range_reverse (i, nid, flags, p_start, p_end, p_nid)
反向遍歷空閒的 memblock 區域
引數
i用作迴圈變數的 u64
nid節點選擇器,
NUMA_NO_NODE表示所有節點flags根據記憶體屬性從塊中選擇
p_start指向 phys_addr_t 的指標,用於範圍的起始地址,可以是
NULLp_end指向 phys_addr_t 的指標,用於範圍的結束地址,可以是
NULLp_nid指向 int 的指標,用於範圍的 nid,可以是
NULL
描述
以相反順序遍歷 memblock 中空閒的(memory && !reserved)區域。Memblock 初始化後即可使用。
-
void memblock_set_current_limit(phys_addr_t limit)¶
設定當前分配限制,以允許將分配限制在啟動期間當前可訪問的範圍。
引數
phys_addr_t limit新的限制值(物理地址)
-
unsigned long memblock_region_memory_base_pfn(const struct memblock_region *reg)¶
獲取記憶體區域的最低 pfn
引數
const struct memblock_region *regmemblock_region 結構體
返回值
與記憶體區域相交的最低 pfn
-
unsigned long memblock_region_memory_end_pfn(const struct memblock_region *reg)¶
獲取記憶體區域的結束 pfn
引數
const struct memblock_region *regmemblock_region 結構體
返回值
保留區域的 end_pfn
-
unsigned long memblock_region_reserved_base_pfn(const struct memblock_region *reg)¶
獲取保留區域的最低 pfn
引數
const struct memblock_region *regmemblock_region 結構體
返回值
與保留區域相交的最低 pfn
-
unsigned long memblock_region_reserved_end_pfn(const struct memblock_region *reg)¶
獲取保留區域的結束 pfn
引數
const struct memblock_region *regmemblock_region 結構體
返回值
保留區域的 end_pfn
-
for_each_mem_region¶
for_each_mem_region (region)
遍歷記憶體區域
引數
region迴圈變數
-
for_each_reserved_mem_region¶
for_each_reserved_mem_region (region)
遍歷保留記憶體區域
引數
region迴圈變數
-
phys_addr_t __init_memblock __memblock_find_range_bottom_up(phys_addr_t start, phys_addr_t end, phys_addr_t size, phys_addr_t align, int nid, enum memblock_flags flags)¶
自下而上查詢空閒區域的工具函式
引數
phys_addr_t start候選範圍的起始
phys_addr_t end候選範圍的結束,可以是
MEMBLOCK_ALLOC_ANYWHERE或MEMBLOCK_ALLOC_ACCESSIBLEphys_addr_t size要查詢的空閒區域的大小
phys_addr_t align要查詢的空閒區域的對齊方式
int nid要查詢的空閒區域的 nid,
NUMA_NO_NODE表示任意節點enum memblock_flags flags根據記憶體屬性從塊中選擇
描述
從 memblock_find_in_range_node() 呼叫的工具函式,自下而上查詢空閒區域。
返回值
成功時返回找到的地址,失敗時返回 0。
-
phys_addr_t __init_memblock __memblock_find_range_top_down(phys_addr_t start, phys_addr_t end, phys_addr_t size, phys_addr_t align, int nid, enum memblock_flags flags)¶
自上而下查詢空閒區域的工具函式
引數
phys_addr_t start候選範圍的起始
phys_addr_t end候選範圍的結束,可以是
MEMBLOCK_ALLOC_ANYWHERE或MEMBLOCK_ALLOC_ACCESSIBLEphys_addr_t size要查詢的空閒區域的大小
phys_addr_t align要查詢的空閒區域的對齊方式
int nid要查詢的空閒區域的 nid,
NUMA_NO_NODE表示任意節點enum memblock_flags flags根據記憶體屬性從塊中選擇
描述
從 memblock_find_in_range_node() 呼叫的工具函式,自上而下查詢空閒區域。
返回值
成功時返回找到的地址,失敗時返回 0。
-
phys_addr_t __init_memblock memblock_find_in_range_node(phys_addr_t size, phys_addr_t align, phys_addr_t start, phys_addr_t end, int nid, enum memblock_flags flags)¶
在給定範圍和節點中查詢空閒區域
引數
phys_addr_t size要查詢的空閒區域的大小
phys_addr_t align要查詢的空閒區域的對齊方式
phys_addr_t start候選範圍的起始
phys_addr_t end候選範圍的結束,可以是
MEMBLOCK_ALLOC_ANYWHERE或MEMBLOCK_ALLOC_ACCESSIBLEint nid要查詢的空閒區域的 nid,
NUMA_NO_NODE表示任意節點enum memblock_flags flags根據記憶體屬性從塊中選擇
描述
在指定的範圍和節點中,查詢大小為 size 並按 align 對齊的空閒區域。
返回值
成功時返回找到的地址,失敗時返回 0。
-
phys_addr_t __init_memblock memblock_find_in_range(phys_addr_t start, phys_addr_t end, phys_addr_t size, phys_addr_t align)¶
在給定範圍中查詢空閒區域
引數
phys_addr_t start候選範圍的起始
phys_addr_t end候選範圍的結束,可以是
MEMBLOCK_ALLOC_ANYWHERE或MEMBLOCK_ALLOC_ACCESSIBLEphys_addr_t size要查詢的空閒區域的大小
phys_addr_t align要查詢的空閒區域的對齊方式
描述
在指定的範圍中,查詢大小為 size 並按 align 對齊的空閒區域。
返回值
成功時返回找到的地址,失敗時返回 0。
-
void memblock_discard(void)¶
如果記憶體和保留陣列已分配,則將其丟棄
引數
void無引數
-
int __init_memblock memblock_double_array(struct memblock_type *type, phys_addr_t new_area_start, phys_addr_t new_area_size)¶
將 memblock 區域陣列的大小加倍
引數
struct memblock_type *type正在加倍的區域陣列的 memblock 型別
phys_addr_t new_area_start要避免重疊的記憶體範圍的起始地址
phys_addr_t new_area_size要避免重疊的記憶體範圍的大小
描述
將 type 區域陣列的大小加倍。如果 memblock 用於為一個新的保留區域陣列分配記憶體,並且存在一個先前已分配的記憶體範圍 [new_area_start, new_area_start + new_area_size] 等待保留,請確保新陣列使用的記憶體不與此範圍重疊。
返回值
成功時返回 0,失敗時返回 -1。
-
void __init_memblock memblock_merge_regions(struct memblock_type *type, unsigned long start_rgn, unsigned long end_rgn)¶
合併相鄰的相容區域
引數
struct memblock_type *type要掃描的 memblock 型別
unsigned long start_rgn從 (start_rgn - 1) 開始掃描
unsigned long end_rgn掃描結束於 (end_rgn - 1)。掃描 type 並在 [start_rgn - 1, end_rgn) 範圍內合併相鄰的相容區域。
-
void __init_memblock memblock_insert_region(struct memblock_type *type, int idx, phys_addr_t base, phys_addr_t size, int nid, enum memblock_flags flags)¶
插入新的 memblock 區域
引數
struct memblock_type *type要插入的 memblock 型別
int idx插入點的索引
phys_addr_t base新區域的基地址
phys_addr_t size新區域的大小
int nid新區域的節點 ID
enum memblock_flags flags新區域的標誌
描述
將新的 memblock 區域 [base, base + size) 插入到 type 的 idx 位置。type 必須已經有足夠的額外空間來容納新區域。
-
int __init_memblock memblock_add_range(struct memblock_type *type, phys_addr_t base, phys_addr_t size, int nid, enum memblock_flags flags)¶
新增新的 memblock 區域
引數
struct memblock_type *type要新增新區域的 memblock 型別
phys_addr_t base新區域的基地址
phys_addr_t size新區域的大小
int nid新區域的 nid
enum memblock_flags flags新區域的標誌
描述
將新的 memblock 區域 [base, base + size) 新增到 type 中。新區域允許與現有區域重疊 - 重疊不會影響已存在的區域。新增後,type 保證是最小的(所有相鄰的相容區域都已合併)。
返回值
成功時返回 0,失敗時返回 -errno。
-
int __init_memblock memblock_add_node(phys_addr_t base, phys_addr_t size, int nid, enum memblock_flags flags)¶
在 NUMA 節點內新增新的 memblock 區域
引數
phys_addr_t base新區域的基地址
phys_addr_t size新區域的大小
int nid新區域的 nid
enum memblock_flags flags新區域的標誌
描述
將新的 memblock 區域 [base, base + size) 新增到“memory”型別中。有關模式詳細資訊,請參閱 memblock_add_range() 的描述。
返回值
成功時返回 0,失敗時返回 -errno。
-
int __init_memblock memblock_add(phys_addr_t base, phys_addr_t size)¶
新增新的 memblock 區域
引數
phys_addr_t base新區域的基地址
phys_addr_t size新區域的大小
描述
將新的 memblock 區域 [base, base + size) 新增到“memory”型別中。有關模式詳細資訊,請參閱 memblock_add_range() 的描述。
返回值
成功時返回 0,失敗時返回 -errno。
-
bool __init_memblock memblock_validate_numa_coverage(unsigned long threshold_bytes)¶
檢查未分配節點 ID 的記憶體量是否小於閾值
引數
unsigned long threshold_bytes可以具有未分配節點 ID 的最大記憶體大小(以位元組為單位)。
描述
有缺陷的韌體可能會報告不屬於任何節點的記憶體。檢查此類記憶體量是否低於 threshold_bytes。
返回值
成功時返回 true,失敗時返回 false。
-
int __init_memblock memblock_isolate_range(struct memblock_type *type, phys_addr_t base, phys_addr_t size, int *start_rgn, int *end_rgn)¶
將給定範圍隔離成不相交的 memblock
引數
struct memblock_type *type要隔離範圍的 memblock 型別
phys_addr_t base要隔離的範圍基址
phys_addr_t size要隔離的範圍大小
int *start_rgn隔離區域起始的輸出引數
int *end_rgn隔離區域結束的輸出引數
描述
遍歷 type 並確保區域不越過 [base, base + size) 定義的邊界。跨越邊界的區域將在邊界處被分割,這最多會建立兩個額外的區域。範圍內的第一個區域的索引在 *start_rgn 中返回,範圍後的第一個區域的索引在 *end_rgn 中返回。
返回值
成功時返回 0,失敗時返回 -errno。
-
void __init_memblock memblock_free(void *ptr, size_t size)¶
釋放啟動記憶體分配
引數
void *ptr啟動記憶體分配的起始地址
size_t size啟動記憶體塊的大小(以位元組為單位)
描述
釋放先前由 memblock_alloc_xx() API 分配的啟動記憶體塊。釋放的記憶體將不會被釋放到夥伴分配器。
-
int __init_memblock memblock_phys_free(phys_addr_t base, phys_addr_t size)¶
釋放啟動記憶體塊
引數
phys_addr_t base啟動記憶體塊的物理起始地址
phys_addr_t size啟動記憶體塊的大小(以位元組為單位)
描述
釋放先前由 memblock_phys_alloc_xx() API 分配的啟動記憶體塊。釋放的記憶體將不會被釋放到夥伴分配器。
-
int __init_memblock memblock_setclr_flag(struct memblock_type *type, phys_addr_t base, phys_addr_t size, int set, int flag)¶
設定或清除記憶體區域的標誌
引數
struct memblock_type *type要設定/清除標誌的 memblock 型別
phys_addr_t base區域的基地址
phys_addr_t size區域的大小
int set設定或清除標誌
int flag要更新的標誌
描述
此函式隔離區域 [base, base + size),並設定/清除標誌。
返回值
成功時返回 0,失敗時返回 -errno。
-
int __init_memblock memblock_mark_hotplug(phys_addr_t base, phys_addr_t size)¶
用 MEMBLOCK_HOTPLUG 標誌標記可熱插拔記憶體。
引數
phys_addr_t base區域的基物理地址
phys_addr_t size區域的大小
返回值
成功時返回 0,失敗時返回 -errno。
-
int __init_memblock memblock_clear_hotplug(phys_addr_t base, phys_addr_t size)¶
清除指定區域的 MEMBLOCK_HOTPLUG 標誌。
引數
phys_addr_t base區域的基物理地址
phys_addr_t size區域的大小
返回值
成功時返回 0,失敗時返回 -errno。
-
int __init_memblock memblock_mark_mirror(phys_addr_t base, phys_addr_t size)¶
用 MEMBLOCK_MIRROR 標誌標記映象記憶體。
引數
phys_addr_t base區域的基物理地址
phys_addr_t size區域的大小
返回值
成功時返回 0,失敗時返回 -errno。
-
int __init_memblock memblock_mark_nomap(phys_addr_t base, phys_addr_t size)¶
用 MEMBLOCK_NOMAP 標誌標記記憶體區域。
引數
phys_addr_t base區域的基物理地址
phys_addr_t size區域的大小
描述
標記有 MEMBLOCK_NOMAP 的記憶體區域將不會被新增到物理記憶體的直接對映中。這些區域仍將由記憶體對映覆蓋。記憶體對映中代表 NOMAP 記憶體幀的 struct page 將是 PageReserved()。
注意
如果正在標記為 MEMBLOCK_NOMAP 的記憶體是從 memblock 分配的,則呼叫方必須通知 kmemleak 忽略該記憶體。
返回值
成功時返回 0,失敗時返回 -errno。
-
int __init_memblock memblock_clear_nomap(phys_addr_t base, phys_addr_t size)¶
清除指定區域的 MEMBLOCK_NOMAP 標誌。
引數
phys_addr_t base區域的基物理地址
phys_addr_t size區域的大小
返回值
成功時返回 0,失敗時返回 -errno。
-
int __init_memblock memblock_reserved_mark_noinit(phys_addr_t base, phys_addr_t size)¶
用 MEMBLOCK_RSRV_NOINIT 標誌標記一個保留記憶體區域,這將導致該區域的 struct pages 不會被初始化。
引數
phys_addr_t base區域的基物理地址
phys_addr_t size區域的大小
描述
對於標記有 MEMBLOCK_RSRV_NOINIT 的保留記憶體區域,struct pages 將不會被初始化。
返回值
成功時返回 0,失敗時返回 -errno。
-
int memblock_mark_kho_scratch(phys_addr_t base, phys_addr_t size)¶
將記憶體區域標記為 MEMBLOCK_KHO_SCRATCH。
引數
phys_addr_t base區域的基物理地址
phys_addr_t size區域的大小
描述
只有標記有 MEMBLOCK_KHO_SCRATCH 的記憶體區域才會在 kexec 移交的早期啟動期間被考慮用於分配。
返回值
成功時返回 0,失敗時返回 -errno。
-
int memblock_clear_kho_scratch(phys_addr_t base, phys_addr_t size)¶
清除指定區域的 MEMBLOCK_KHO_SCRATCH 標誌。
引數
phys_addr_t base區域的基物理地址
phys_addr_t size區域的大小
返回值
成功時返回 0,失敗時返回 -errno。
-
void __next_mem_range(u64 *idx, int nid, enum memblock_flags flags, struct memblock_type *type_a, struct memblock_type *type_b, phys_addr_t *out_start, phys_addr_t *out_end, int *out_nid)¶
用於
for_each_free_mem_range()等的下一個函式。
引數
u64 *idx指向u64迴圈變數的指標
int nid節點選擇器,
NUMA_NO_NODE表示所有節點enum memblock_flags flags根據記憶體屬性從塊中選擇
struct memblock_type *type_a指向獲取記憶體範圍的memblock_type的指標
struct memblock_type *type_b指向排除記憶體的memblock_type的指標
phys_addr_t *out_start指向 phys_addr_t 的指標,用於範圍的起始地址,可以是
NULLphys_addr_t *out_end指向 phys_addr_t 的指標,用於範圍的結束地址,可以是
NULLint *out_nid指向 int 的指標,用於範圍的 nid,可以是
NULL
描述
從 *idx 中找到第一個匹配 nid 的區域,填充輸出引數,並更新 *idx 以供下一次迭代。 *idx 的低32位包含type_a的索引,高32位索引type_b中每個區域之前的區域。例如,如果type_b區域如下所示:
0:[0-16), 1:[32-48), 2:[128-130)
高32位索引以下區域。
0:[0-0), 1:[16-32), 2:[48-128), 3:[130-MAX)
由於兩個區域陣列都已排序,函式會同步推進兩個索引並返回每個交集。
-
void __init_memblock __next_mem_range_rev(u64 *idx, int nid, enum memblock_flags flags, struct memblock_type *type_a, struct memblock_type *type_b, phys_addr_t *out_start, phys_addr_t *out_end, int *out_nid)¶
for_each_*_range_rev() 的通用下一個函式
引數
u64 *idx指向u64迴圈變數的指標
int nid節點選擇器,
NUMA_NO_NODE表示所有節點enum memblock_flags flags根據記憶體屬性從塊中選擇
struct memblock_type *type_a指向獲取記憶體範圍的memblock_type的指標
struct memblock_type *type_b指向排除記憶體的memblock_type的指標
phys_addr_t *out_start指向 phys_addr_t 的指標,用於範圍的起始地址,可以是
NULLphys_addr_t *out_end指向 phys_addr_t 的指標,用於範圍的結束地址,可以是
NULLint *out_nid指向 int 的指標,用於範圍的 nid,可以是
NULL
描述
從type_a中找到未在type_b中標記為不適合的下一個範圍。
-
int __init_memblock memblock_set_node(phys_addr_t base, phys_addr_t size, struct memblock_type *type, int nid)¶
設定memblock區域的節點ID
引數
phys_addr_t base要設定節點ID的區域的基地址
phys_addr_t size要設定節點ID的區域的大小
struct memblock_type *type要設定節點ID的memblock型別
int nid要設定的節點ID
描述
將memblock type 區域在 [base, base + size) 範圍內的節點ID設定為 nid。必要時,跨區域邊界的區域會被分割。
返回值
成功時返回 0,失敗時返回 -errno。
-
void __init_memblock __next_mem_pfn_range_in_zone(u64 *idx, struct zone *zone, unsigned long *out_spfn, unsigned long *out_epfn)¶
for_each_*_range_in_zone()的迭代器
引數
u64 *idx指向u64迴圈變數的指標
struct zone *zone所有記憶體塊所在的區域
unsigned long *out_spfn指向 ulong 的指標,用於範圍的起始 pfn,可以是
NULLunsigned long *out_epfn指向 ulong 的指標,用於範圍的結束 pfn,可以是
NULL
描述
此函式旨在作為for_each_mem_range型別迭代器的 zone/pfn 特定包裝器。它們專門用於延遲記憶體初始化例程中,因此我們在整個程式碼中重複了許多相同的邏輯。因此,與其在多個位置擁有它,不如將其集中到一個新的迭代器中,該迭代器可以完成它們所需的一切,這似乎更有意義。
-
phys_addr_t memblock_alloc_range_nid(phys_addr_t size, phys_addr_t align, phys_addr_t start, phys_addr_t end, int nid, bool exact_nid)¶
分配引導記憶體塊
引數
phys_addr_t size要分配的記憶體塊的大小(位元組)
phys_addr_t align區域和塊大小的對齊
phys_addr_t start要分配的記憶體區域的下界(物理地址)
phys_addr_t end要分配的記憶體區域的上界(物理地址)
int nid要查詢的空閒區域的 nid,
NUMA_NO_NODE表示任意節點bool exact_nid控制分配是否回退到其他節點
描述
如果 end == MEMBLOCK_ALLOC_ACCESSIBLE,則從 memblock.current_limit 限制的記憶體區域進行分配。
如果指定的節點無法容納請求的記憶體且 exact_nid 為 false,則分配將回退到系統中的任何節點。
對於具有記憶體映象的系統,首先嚐試從啟用映象的區域分配,然後從任何記憶體區域重試。
此外,函式使用 kmemleak_alloc_phys 分配引導記憶體塊,它永不報告為洩漏。
返回值
成功時為分配的記憶體塊的物理地址,失敗時為0。
-
phys_addr_t memblock_phys_alloc_range(phys_addr_t size, phys_addr_t align, phys_addr_t start, phys_addr_t end)¶
在指定範圍內分配記憶體塊
引數
phys_addr_t size要分配的記憶體塊的大小(位元組)
phys_addr_t align區域和塊大小的對齊
phys_addr_t start要分配的記憶體區域的下界(物理地址)
phys_addr_t end要分配的記憶體區域的上界(物理地址)
描述
在 start 和 end 之間分配 size 位元組。
返回值
成功時返回分配的記憶體塊的物理地址,失敗時返回0。
-
phys_addr_t memblock_phys_alloc_try_nid(phys_addr_t size, phys_addr_t align, int nid)¶
從指定的NUMA節點分配記憶體塊
引數
phys_addr_t size要分配的記憶體塊的大小(位元組)
phys_addr_t align區域和塊大小的對齊
int nid要查詢的空閒區域的 nid,
NUMA_NO_NODE表示任意節點
描述
從指定的NUMA節點分配記憶體塊。如果該節點沒有可用記憶體,則嘗試從系統中的任何節點分配。
返回值
成功時返回分配的記憶體塊的物理地址,失敗時返回0。
-
void *memblock_alloc_internal(phys_addr_t size, phys_addr_t align, phys_addr_t min_addr, phys_addr_t max_addr, int nid, bool exact_nid)¶
分配引導記憶體塊
引數
phys_addr_t size要分配的記憶體塊的大小(位元組)
phys_addr_t align區域和塊大小的對齊
phys_addr_t min_addr要分配的記憶體區域的下界(物理地址)
phys_addr_t max_addr要分配的記憶體區域的上界(物理地址)
int nid要查詢的空閒區域的 nid,
NUMA_NO_NODE表示任意節點bool exact_nid控制分配是否回退到其他節點
描述
使用memblock_alloc_range_nid()分配記憶體塊,並將返回的物理地址轉換為虛擬地址。
如果無法滿足 min_addr 限制,則會放棄該限制,並回退到 min_addr 以下的記憶體進行分配。其他約束,例如節點和映象記憶體,將再次在memblock_alloc_range_nid()中處理。
返回值
成功時返回分配的記憶體塊的虛擬地址,失敗時返回NULL。
-
void *memblock_alloc_exact_nid_raw(phys_addr_t size, phys_addr_t align, phys_addr_t min_addr, phys_addr_t max_addr, int nid)¶
在精確節點上分配引導記憶體塊,不清零記憶體
引數
phys_addr_t size要分配的記憶體塊的大小(位元組)
phys_addr_t align區域和塊大小的對齊
phys_addr_t min_addr優先從中分配記憶體區域的下界(物理地址)
phys_addr_t max_addr優先從中分配記憶體區域的上界(物理地址),或者
MEMBLOCK_ALLOC_ACCESSIBLE表示僅從memblock.current_limit值限制的記憶體中分配int nid要查詢的空閒區域的 nid,
NUMA_NO_NODE表示任意節點
描述
公共函式,如果啟用,提供額外的除錯資訊(包括呼叫者資訊)。不清零已分配的記憶體。
返回值
成功時返回分配的記憶體塊的虛擬地址,失敗時返回NULL。
-
void *memblock_alloc_try_nid_raw(phys_addr_t size, phys_addr_t align, phys_addr_t min_addr, phys_addr_t max_addr, int nid)¶
分配引導記憶體塊,不清零記憶體且不發生panic
引數
phys_addr_t size要分配的記憶體塊的大小(位元組)
phys_addr_t align區域和塊大小的對齊
phys_addr_t min_addr優先從中分配記憶體區域的下界(物理地址)
phys_addr_t max_addr優先從中分配記憶體區域的上界(物理地址),或者
MEMBLOCK_ALLOC_ACCESSIBLE表示僅從memblock.current_limit值限制的記憶體中分配int nid要查詢的空閒區域的 nid,
NUMA_NO_NODE表示任意節點
描述
公共函式,如果啟用,提供額外的除錯資訊(包括呼叫者資訊)。不清零已分配的記憶體,如果請求無法滿足則不發生panic。
返回值
成功時返回分配的記憶體塊的虛擬地址,失敗時返回NULL。
-
void *memblock_alloc_try_nid(phys_addr_t size, phys_addr_t align, phys_addr_t min_addr, phys_addr_t max_addr, int nid)¶
分配引導記憶體塊
引數
phys_addr_t size要分配的記憶體塊的大小(位元組)
phys_addr_t align區域和塊大小的對齊
phys_addr_t min_addr優先從中分配記憶體區域的下界(物理地址)
phys_addr_t max_addr優先從中分配記憶體區域的上界(物理地址),或者
MEMBLOCK_ALLOC_ACCESSIBLE表示僅從memblock.current_limit值限制的記憶體中分配int nid要查詢的空閒區域的 nid,
NUMA_NO_NODE表示任意節點
描述
公共函式,如果啟用,提供額外的除錯資訊(包括呼叫者資訊)。此函式會將已分配的記憶體清零。
返回值
成功時返回分配的記憶體塊的虛擬地址,失敗時返回NULL。
-
void *__memblock_alloc_or_panic(phys_addr_t size, phys_addr_t align, const char *func)¶
嘗試分配記憶體並在失敗時panic
引數
phys_addr_t size要分配的記憶體塊的大小(位元組)
phys_addr_t align區域和塊大小的對齊
const char *func呼叫函式名
描述
此函式嘗試使用memblock_alloc分配記憶體,如果失敗,則會使用格式化的訊息呼叫panic。此函式不應直接使用,請使用宏memblock_alloc_or_panic。
-
void memblock_free_late(phys_addr_t base, phys_addr_t size)¶
直接將頁面釋放到buddy分配器
引數
phys_addr_t base啟動記憶體塊的物理起始地址
phys_addr_t size啟動記憶體塊的大小(以位元組為單位)
描述
這僅在memblock分配器已被拆除但系統仍在初始化時有用。頁面直接釋放到buddy分配器。
-
unsigned long memblock_estimated_nr_free_pages(void)¶
從memblock角度返回估計的空閒頁面數
引數
void無引數
描述
在啟動期間,子系統可能需要在buddy提供精確數字之前,獲得整個系統中空閒頁面的粗略估計。尤其是在啟用CONFIG_DEFERRED_STRUCT_PAGE_INIT的情況下,從buddy獲得的數字在啟動期間可能非常不精確。
返回值
從memblock角度估計的空閒頁面數。
-
bool __init_memblock memblock_is_region_memory(phys_addr_t base, phys_addr_t size)¶
檢查區域是否為記憶體的子集
引數
phys_addr_t base要檢查區域的基地址
phys_addr_t size要檢查區域的大小
描述
檢查區域 [base, base + size) 是否為記憶體塊的子集。
返回值
如果為false則返回0,如果為true則返回非零值
-
bool __init_memblock memblock_is_region_reserved(phys_addr_t base, phys_addr_t size)¶
檢查區域是否與保留記憶體相交
引數
phys_addr_t base要檢查區域的基地址
phys_addr_t size要檢查區域的大小
描述
檢查區域 [base, base + size) 是否與保留記憶體塊相交。
返回值
如果相交則為True,否則為False。
-
void memblock_free_all(void)¶
將空閒頁面釋放到buddy分配器
引數
void無引數
-
int reserve_mem_find_by_name(const char *name, phys_addr_t *start, phys_addr_t *size)¶
透過名稱查詢保留記憶體區域
引數
const char *name附加到保留記憶體區域的名稱
phys_addr_t *start如果找到,儲存起始地址
phys_addr_t *size如果找到,儲存地址的大小。
描述
只有當找到 name 時,start 和 size 才會更新。
返回值
如果找到則為1,如果未找到則為0。
-
int reserve_mem_release_by_name(const char *name)¶
釋放具有給定名稱的保留記憶體區域
引數
const char *name附加到保留記憶體區域的名稱
描述
強制釋放保留記憶體區域中的頁面,以便這些記憶體可以用作空閒記憶體。釋放後,保留區域的大小變為0。
返回值
如果釋放則為1,如果未找到則為0。