記憶體模型

_xingxing發表於2024-11-20

前言

不是特別懂,但是先把自己目前的理解寫下來(甚至目前的有些理解都是錯的),隨著時間的積累再豐富;

記憶體模型

有三種記憶體模型:

  • Flat Memory:所有記憶體都是連續的,透過陣列管理所有的page,陣列的下標就是pfn;所有可以很簡單的pfn下標找到對應的page,page可以很簡單的找到pfn;
  • Discontiguous Memory:非連續記憶體;沒有深入研究,透過node管理page,一個node中page都是連續的;
  • Sparse Memory:稀疏記憶體模型;集中關注這裡;

sparse memory

管理思想

存在一個struct mem_section **mem_section的全域性變數,該變數是一個二級指標;
sparse_index_init函式可以看出mem_section的組織形式;
sparse_index_init中使用sparse_index_alloc分配struct mem_section的記憶體,然後賦值給mem_section全域性變數進行儲存;

  • 所以首先可以確定 *mem_section 指向了一個實際的地址,那*mem_section是一個簡單的變數地址,還是一個陣列的地址呢?(C語言一個指標比如int *p,這個p可能是一個變數的地址,也有可能是一個陣列的地址)

sparse_index_alloc可以瞭解
裡面這個記憶體分配的大小是 SECTIONS_PER_ROOT * sizeof(struct mem_section),也就是說這個一級指標指向了一個實際的陣列,這個陣列的長度是 SECTIONS_PER_ROOT;可以同時計算出array_size是一個page的大小;
那麼mem_section的組織形式就出來了:

如何透過mem_section,進行pfn和page的相互轉化

mem_section的section_mem_map存放了該section的起始page(__section_mem_map_addr)
所以__section_mem_map_addr + pfn就是對應的page;
page-__section_mem_map_addr = pfn;

原始碼實現

建立

arm64_memory_present中遍歷memblock,進行memory_present,memory_present中完成了記憶體的建立

初始化

sparse_init,->sparse_init_nid:
struct page *map,估計就是page,spares_init_one_section,ms->section_mem_map進行了初始page的賦值;

no-map 為什麼會報錯

現象:

  • 使用phys_to_page獲取page;再使用page_to_phys將page轉化為phys,出錯;
    page_to_phys 核心是 __page_to_pfn->page_to_section,page_to_section獲取section依賴於page->flag;訪問flga成員時候出先空指標;
  • 使用者空間分配一個較大的全域性變數時,沒有該問題;

原因分析

  • no-map的記憶體並沒有加入夥伴系統,可以理解為no-map自己實現了一套記憶體管理方法,它的記憶體管理只是簡單的bitmap置位管理,虛擬地址是透過ioremap獲取的,與實體地址是一個簡單的偏移;
  • __fdt_scan_reserved_mem掃描reserved-memory->__reserved_mem_reserve_reg的時候,會把no-map記憶體屬性的memory從memblock移除掉(early_init_dt_reserve_memory_arch),不是no-map的進行reserve;
  • arm64_memory_present只會對memblock管理的地址進行pfn對應section的建立,所以no-map沒有進行管理,進而使用page_to_pfn就會出錯;
    可以從兩個方面理解:1是它沒有實際的page;2是它並沒有被memblock管理然後建立;

針對現象進行分析

瞭解了原因之後,分析為什麼有這麼一個現象;

1是沒有實際的page

phys_to_page得到的一個page就是一個錯誤的page,誤打誤撞到了使用者空間的一個地址,所以當使用者空間有一個較大的全域性變數時,就不會報錯;但是結果有錯;

2是它並沒有被memblock管理然後建立

由於page是一個錯誤的page,那後面的訪問flag操作就自然而然錯誤了;

解決方法

直接獲取實體地址

不使用pfn_to_page,直接特殊判斷使用實體地址;

能否透過配置修復

相關文章