OK6410A 开发板 (八) 35 linux-5.11 OK6410A 内存管理第三阶段

发布者:reaper2009最新更新时间:2022-09-07 来源: csdn关键字:OK6410A  开发板  11  内存管理 手机看文章 扫描二维码
随时随地手机看文章

C setup_arch->paging_init->bootmem_init->memblock_allow_resize返回  - mm_init->mem_init返回

----此时memblock消亡,buddy初始化完成,开启了基于虚拟内时代的 buddy内存管理器时代


流程

setup_arch(&command_line);->paging_init

bootmem_init

find_limits(&min_low_pfn, &max_low_pfn, &max_pfn);

sparse_init

zone_sizes_init(min_low_pfn, max_low_pfn, max_pfn);

// 申请 struct page 所在的空间

free_area_init(max_zone_pfn);

pg_data_t *pgdat = NODE_DATA(nid); // &contig_page_data

free_area_init_node(nid);

alloc_node_mem_map(pgdat); // struct page 相关的配置

struct page * map = memblock_alloc_node(size, SMP_CACHE_BYTES, pgdat->node_id);

// 为 struct page 申请空间

// struct page 的个数 为 (6000 0000 - 5000 0000)/0x1000

// memblock_reserve: [0x5fdf6000-0x5fff5fff]

// 20 0000 个字节

// 一个 struct page 为 0x20 字节

// (6000 0000 - 5000 0000)/0x1000 * 0x20

// 申请的起始地址为 cfdf6000 , 大小为 0x20 0000

pgdat->node_mem_map = map + offset;

// map : cfdf6000

// offset : 0

// pgdat->node_mem_map : cfdf6000

mem_map = NODE_DATA(0)->node_mem_map;

// mem_map = pgdat->node_mem_map = cfdf6000




free_area_init_core(pgdat); // zone相关的设置

struct zone *zone = pgdat->node_zones + j;

zone_init_internals(zone, j, nid, freesize);

setup_usemap(pgdat, zone, zone_start_pfn, size);

// 申请一块地址,大小 0x20

// 作用是什么 ? 返回的起始地址 是 0x5fffddc0,对应虚拟地址是 0xcfffddc0

// memblock_reserve: [0x5fffddc0-0x5fffdddf]

// 返回的虚拟地址 存储到 了 zone->pageblock_flags 中 

init_currently_empty_zone

zone_init_free_lists(zone);

// order 取值范围 为 [0,...,MAX_ORDER(11)]

// t 取值范围 为 [MIGRATE_UNMOVABLE(0), ... MIGRATE_TYPES(8)]

INIT_LIST_HEAD(&zone->free_area[order].free_list[t]);

zone->free_area[order].nr_free = 0;

zone->initialized = 1;

memmap_init(size, nid, j, zone_start_pfn); // 将 创建的 (6000 0000 - 5000 0000)/0x1000 * 0x20 个 struct page 一次 遍历,并 reserved

start_pfn = 50000;

end_pfn = 60000;

size = end_pfn - start_pfn;

memmap_init_zone(size, nid, zone, start_pfn, range_end_pfn, MEMINIT_EARLY, NULL, MIGRATE_MOVABLE);

page = pfn_to_page(pfn);

if (IS_ALIGNED(pfn, pageblock_nr_pages)) set_pageblock_migratetype(page, migratetype);

empty_zero_page = virt_to_page(zero_page); // empty_zero_page 为 cfff5ec0

// 之前 zero_page = early_alloc(PAGE_SIZE);

// zero_page 为 cfff6000

// 申请的空间刚好在 全部的 struct page  上面

// 申请了 一物理页(4096B) 空间,返回了 虚拟地址 

// 以 虚拟地址 zero_page  得到 对应这块地址的 struct page 即 empty_zero_page

// 函数过程

// 1. 根据 虚拟地址 zero_page 获取 物理地址A

// 2. 根据 物理地址A 右移 12 , 获取 pfn

// 3. 根据 pfn 获取 返回 (mem_map + ((pfn) - ARCH_PFN_OFFSET)) // ARCH_PFN_OFFSET = 50000

// 4. mem_map 是 第一个page 的地址,结构体 类型为 struct page

// 5. 返回的是 一个 struct page 的结构体变量地址



// TODO

__flush_dcache_page(NULL, empty_zero_page);

// 将缓存中保存的数据向内存执行回写

// 从而将缓存内容反映到内存,以此确保缓存和内存间的一致性

// 这里是写了什么 ??? TODO

/*

setup_processor

struct proc_info_list *list = lookup_processor(midr); // __v6_proc_info

cpu_cache = *list->cache; // v6_cache_fns

__flush_dcache_page

if (!PageHighMem(page)) __cpuc_flush_dcache_area(page_address(page), page_size(page)); 

// 即 v6_flush_kern_dcache_area , 下面有 对 v6_flush_kern_dcache_area 的 重点解析,全局搜索

// page_address(page) : cfff 6000

// page_size(page)   : 0x1000

*/


setup_arch

request_standard_resources(mdesc);

// 按照树状结构 注册 内存 kernel_code kernel_data


// TODO

build_all_zonelists


// TODO

page_alloc_init

// 订阅 CPUHP_PAGE_ALLOC_DEAD 信息

// 注册 CPUHP_PAGE_ALLOC_DEAD 发布时的处理函数 page_alloc_cpu_dead

// linux-2.6.30.4 是 notify chain机制, cpu_chain

mm_init

page_ext_init_flatmem

init_mem_debugging_and_hardening

report_meminit


// TODO

mem_init

set_max_mapnr(pfn_to_page(max_pfn) - mem_map);

max_mapnr = struct page 的个数(包括空洞的)

memblock_free_all

free_unused_memmap

// 释放 memblock 块 之间的空洞部分

// 例如 memblock_add 了三块

// 0 - 0x1000 0000

// 0x2000 0000 - 0x3000 0000

// 0x5000 0000 - 0x6000 0000

// 那么 0x1000 0000 - 0x2000 0000 就是空洞

// 那么 0x3000 0000 - 0x5000 0000 也是空洞

// 第一块空洞对应 下面的函数调用

// prev_end = 0x1000 0

// start = 0x2000 0

// free_memmap(prev_end, start); 

// free_memmap -> memblock_free

// memblock_free 把一个逻辑块从memblock.reserved 移除

// free_unused_memmap  移除的 是 struct page 所在的地址

// 也就是之前 为 0x1000 0000 - 0x2000 0000 ,即 0x2000 0000 - 0x1000 0000 = 0x1000 0000 大小的空间建立了 

// 0x1000 0000/0x1000 = 0x10000 个 struct page

// 这 0x10000 * sizeof(struct page) = 0x10000 * 0x20 = 0x200000

// 空间, 是之前 memblock_alloc 申请的

// 但是 这些空间的struct page 没有用(因为对应空洞物理页)

// 所以将他们释放了

reset_all_zones_managed_pages

// 初始化 contig_page_data.node_zones[].managed_pages 为 0

free_low_memory_core_early

for_each_reserved_mem_range(i, &start, &end) reserve_bootmem_region(start, end);

for_each_pfn do{

init_reserved_page(pfn); // null

INIT_LIST_HEAD(&page->lru);

__SetPageReserved(page);

}

// 针对 memblock.reserved 中的 每一块 reserved 内存

// 将内存对应的 struct page 的 flags 成员 __SetPageReserved

// 被 __SetPageReserved 的 物理页 永远不会 被 当做是 可申请的内存 

// 被 __SetPageReserved 的 物理页 不在 buddy 的内存管理范围内

for_each_free_mem_range __free_memory_core(start, end);

__free_pages_memory

memblock_free_pages

// 不同于 memblock_free

// struct page *page,  : 参数1 : page的地址

// unsigned long pfn, : 参数2 : page frame number

// unsigned int order : 参数3 : order : 如果为0 表示 2^0 (即1) 个页 

__free_pages_core

// struct page *page,  : 参数1 : page的地址

// unsigned int order : 参数2 : order : 如果为0 表示 2^0 (即1) 个页 

__ClearPageReserved

__free_pages_ok

free_one_page

__free_one_page

// 针对 memblock.memory 中 memblock.reserved 的补集 中的每一块 内存

// 将内存对应的 struct page 加入到 free_list

totalram_pages_add

atomic_long_add(count, &_totalram_pages);

// 之前 是 0 

// 现在 是 ee39

// end   start num

// 50004  50000 4

// 50100  50008 F8

// 5fdbd  51081 ED3C

// 5fdf6  5fdf5 1

// 5fffd  5fffe 1


free_highpages

// null

mem_init_print_info

// 打印如下信息

// ]Memory: 243940K/262144K available (5120K kernel code, 6569K rwdata, 736K rodata, 1024K init, 2134K bss, 18204K reserved, 0K cma-reserved)

// 这里本来应有 Virtual kernel memory layout 的打印

// 但是 去掉了,下面为linux中的commit id

// 1c31d4e96b8c205fe3aa8e73e930a0ccbf4b9a2b


memblock 向 buddy 过渡的本质

memblock 时代 物理内存和虚拟内存是怎么管控的

1. 页表(物理地址到虚拟地址的映射)

// 对应下面的 early map 类 和 map 类

2. 按区域 注册物理内存到 memblock 内存管理器中的 memblock 变量

// 对应下面的 memblock 类

buddy 时代 物理内存和虚拟内存是怎么管控的

1. 页表(物理地址到虚拟地址的映射)

2. 按物理页 注册物理内存到 buddy 内存管理器中的 struct page


memblock 切换 到 buddy , 只需要做

1. 不需要做页表的映射(因为memblock时代,已经做完了,buddy直接用就行了)

2. 将 注册到memblock内存管理器memblock变量中 的 物理页 注册到 buddy内存管理器中的struct page


另一个角度看 buddy 初始化

zone_sizes_init

A B C D E F K

build_all_zonelists

G H I J

mem_init

E F L

reset_all_zones_managed_pages

L


这几个函数主要是 初始化 struct pglist_data contig_page_data; 变量 的成员及 成员的成员


struct pglist_data // A

struct zone node_zones[MAX_NR_ZONES]; // B

atomic_long_t       managed_pages; // L

unsigned long       zone_start_pfn; // C

struct free_area    free_area[MAX_ORDER]; // D

struct list_head    free_list[MIGRATE_TYPES]; // E

unsigned long       nr_free; // F

struct zonelist node_zonelists[MAX_ZONELISTS]; // G

struct zoneref _zonerefs[MAX_ZONES_PER_ZONELIST + 1];// H

struct zone *zone; // I

int zone_idx; // J

struct page *node_mem_map; // K

重点函数解析

v6_flush_kern_dcache_area

/*

 * v6_flush_kern_dcache_area(void *addr, size_t size)

 *

 * Ensure that the data held in the page kaddr is written back

 * to the page in question.

 *

 * - addr - kernel address

 * - size - region size

 */

ENTRY(v6_flush_kern_dcache_area)

// r0 = cfff 6000

// r1 = 0x1000

add r1, r0, r1

// r1 = cfff 7000

bic r0, r0, #D_CACHE_LINE_SIZE - 1

// D_CACHE_LINE_SIZE = 32

// 32 -1 = 1F

// r0 = r0 bit_clear 1F = cfff 6000



// HARVARD_CACHE 已经 define


1:

#ifdef HARVARD_CACHE

mcr p15, 0, r0, c7, c14, 1 @ clean & invalidate D line

// 写cp15 c7

// 写入的数据 依次是 

// cfff 6000

// cfff 6020

// cfff 6040

// ...

// cfff 6fe0


// 作用是 Clean and invalidate data cache line

// Clean :

// 适用于write back 数据缓存

// 意味着如果缓存线包含尚未写入主内存的存储数据,则它现在将写入主内存

// 并且该行被标记为干净。

// invalidate :

// 表示缓存线(或缓存中的所有行)被标记为无效。

// 在将该行重新分配到某个地址之前,该行不会发生缓存命中。

// 对于写回数据缓存,这不包括清除缓存线,除非另有说明。

// cache line :

// 为了尽量减少控制信息的存储量,空间局部性属性用于将多个位置分组到同一标签下。

// 这个内存位置的逻辑块通常称为缓存线,通常为32字节长。


// Cache写机制分为write through和write back两种

// write back :

// Write-back(回写模式)在数据更新时只写入缓存Cache。

// 只在数据被替换出缓存时,被修改的缓存数据才会被写到后端存储。

// 此模式的优点是数据写入速度快,因为不需要写存储;

// 缺点是一旦更新后的数据未被写入存储时出现系统掉电的情况,数据将无法找回。

// Write-through : 

// Write-through(直写模式)在数据更新时,同时写入缓存Cache和后端存储。

// 此模式的优点是操作简单;缺点是因为数据修改需要同时写入存储,数据写入速度较慢


// cache 写机制 之前被设置成了什么 ?? TODO

// early_mm_init 中有打印 

// Memory policy: Data cache writeback

// early_mm_init 中不是设置,而是显示,设置在哪里,TODO

// write back 的设置有几个设置点

// 1. cp15 c1 // 控制开 write buffer/cache

// 2. pmd // 控制 pmd的bit[3:2] 为 11 

// 3. pte // 控制 pte的bit[3:2] 为 11



// 内存 cfff 6000 - cfff 7000 被加载入缓存

// 如果 缓存中的数据有变化,但是 因为 cache 机制 为 write back, 所以此时还没写入内存

// mcr p15, 0, r0, c7, c14, 1 作用是

// 将 缓存中的数据写到 内存 cfff 6000 - cfff 7000


// 但是 内存 cfff 6000 - cfff 7000 中的数据 在 该操作前后 全部为 0(前后一致) 

// 也就是说 没有修改过 内存 cfff 6000 - cfff 7000, 为什么还要 做cache 与内存的同步

#else

#endif

add r0, r0, #D_CACHE_LINE_SIZE

// D_CACHE_LINE_SIZE = 32 = 0x20

cmp r0, r1

blo 1b


// r0 < r1 则跳转

#ifdef HARVARD_CACHE

mov r0, #0

mcr p15, 0, r0, c7, c10, 4

// 写 cp15 c7

// 写入的数据是 0


// Data Synchronization Barrier (formerly Drain Write Buffer)

// Data synchronization barrier :

// 以前的数据写屏障,数据写载体(DWB),现在叫DSB

// 数据同步屏障可以在特权和用户操作模式下执行


// B2.6.2数据同步屏障(DSB)

// 特点:

// 在DSB完成之前,DSB后面的任何指令都不能执行。


// CP15寄存器7注:该操作历来被称为DrainWriteBuffer或DataWriteBarrier(DWB)。

[1] [2]
关键字:OK6410A  开发板  11  内存管理 引用地址:OK6410A 开发板 (八) 35 linux-5.11 OK6410A 内存管理第三阶段

上一篇:OK6410A 开发板 (八) 36 linux-5.11 OK6410A 内存管理第四阶段
下一篇:OK6410A 开发板 (八) 34 linux-5.11 OK6410A 内存管理第二阶段

推荐阅读最新更新时间:2024-11-05 12:31

苹果iPhone 11、iPhone X Plus等三款真机模型上手
根据此前爆料消息,今年苹果将发布三款iPhone新品,分别是升级版iPhone XI(或称iPhone 11)、配置6.5英寸OLED显示屏的iPhone X Plus、配置6.1英寸LCD显示屏的中档iPhone型号,这款6.1英寸iPhone支持无边框设计和面容ID,但价格更低。   现在这三款iPhone的真机模型图被曝光,其中iPhone XI(也就是iPhone 11)依然小型尺寸机身,6.1英寸版iPhone在中间,采用后置单摄镜头,最右边是配置6.5英寸OLED显示屏的iPhone X Plus。   可以看出三款手机都采用了刘海屏设计,看来苹果暂时不会更改使用新的全面屏设计,并且两款手机屏幕超过了6英寸,iPh
[手机便携]
单片机对12M和11.0592M的选择
1单片机常用晶振频率是1.2M-12M,一般情况下,一个机器周期是12个时钟周期,所以用12M时,一个机器周期是1US,好计算,而且速度相对是最高的,当然现在也有更高频率的单片机。 而进行通信是,一般选择11.0592M,12M频率进行串行通信不容易实现标准的波特率,比如9600,4800,而11.0592M计算时正好可以得到,因此在有通信接口的单片机中,一般选11.0592M 计算一下就知道了。如我们要得到9600 的波特率,晶振为11.0592M 和12M,定时器1 为模式2,SMOD 设为1,分别看看那所要求的TH1 为何值。 代入公式: 11.0592M 9600=(2 32)
[单片机]
蔚来首款量产车官方图片发布,携11辆车亮相上海车展
    4 月 5 日,蔚来发布首款量产车 ES8 的官方局部图片。据蔚来官方消息,在上海车展期间蔚来将携 11 辆车集体亮相。这其中包括蔚来 Formula E 赛车、EP9 电动超跑、EVE 概念车以及首款量产车 ES8。   这家成立于 2014 年的初创电动汽车公司,在近一年时间里给外界带来了不少惊喜。   2015 年蔚来车队获得 FIA Formula E 历史上首个车手总冠军、去年 10 月蔚来发布的「全球最快电动汽车」EP9(全球 6 辆,价值 120 万美元),创造纽博格林北环等 4 个国际知名赛道最快圈速纪录,西南偏南(SXSW)上发布发布了首款概念车 EVE。接下来则是首款量产车型 ES8 首次亮相上海车展。
[汽车电子]
移动通信设备营业收入2011年预计强劲增长29%
     据IHS iSuppli公司的无线通信市场研究报告,智能手机和平板电脑在消费者中日益普及,今年将推动移动通信产品与无线基础设施设备营业收入大增29%。 预计2011年总体移动通信设备市场营业收入将达到3356亿美元,高于2010年的2599亿美元。今年的增长率将超过2010年的19%,亦将至少是2015年前这几年的最高增长率。预计2015年营业收入将突破5000亿美元,如图所示。 IHS公司认为,随着假日销售季开始,苹果iPhone和iPad等3.5G和4G设备将继续促进该领域的增长。更重要的是,这些产品以及其它多种移动通信设备所创造及引发的数据消费需求,将对总体无线生态系统产生深远的影响,推动各方面的发展,从芯
[工业控制]
STM8操作LCD5110总结
附上一小段代码: void LCD_init(void) { // 产生一个让LCD复位的低电平脉冲 //LCD_RST = 0; GPIO_WriteLow(LCD_PORTG, LCD_RST); delay_1us(); //LCD_RST = 1; GPIO_WriteHigh(LCD_PORTG, LCD_RST); // 关闭LCD //LCD_CE = 0; GPIO_WriteLow(LCD_PORTG, LCD_CE); delay_1us(); // 使能LCD // LCD_CE = 1; GPIO_WriteHigh(LCD_PORTG, LCD_CE); delay_1us(); LCD_write_by
[单片机]
STM8操作LCD5<font color='red'>11</font>0总结
LED照明产品2011年有望被列入中国“节能产品惠民工程”补贴之列
    2011年年初中国发改委、财政部联合修改“节能产品政府采购实施意见,调整“节能产品惠民工程”补贴,LED照明产品有望被纳入补贴范围之列。     业内人士指出,节能产品惠民工程在2009年就实施,2011年新增LED照明,鼓励民众未来购买LED产品,可望获得政府的补助,补助的金额最高中央有50%,地方政府则有30%。     同时,大陆各地方政府目前在节能减碳的落实上都有压力,必须借重台湾LED厂的实力,但又止不希望由台厂来主导,因此大多数愿意以权利金的方式支付,对台厂是一大利基。
[电源管理]
九洲集团与泰来县签约 在丹顶鹤建110MW/220MWh储能电站项目
  2月6日,泰来县政府与九洲集团举行泰来县丹顶鹤110MW/220MWh储能电站项目签约仪式。九洲集团董事长李寅、国家电投集团上海融和元储能源有限公司副总经理夏雨,县委书记张大民,县委副书记、县长郑德利,县人大常委会主任赫萍,副县长姜兴业和相关部门负责同志出席签约仪式。   仪式上,九洲集团董事长李寅介绍签约项目情况,并表示,泰来县丹顶鹤110MW/220MWh储能电站项目建设在泰来,不仅是因为看到了这里明显的区位资源优势,更是看中了这里良好的投资环境。企业将与泰来县深度对接,把合作事项落细落实,共同推动合作项目落地生根、开花结果,为泰来地方经济发展作出积极贡献。   随后,县委副书记、县
[新能源]
欧德宁:2011年推首款英特尔处理器智能手机
据国外媒体报道,英特尔CEO欧德宁(Paul Otellini)周三表示,英特尔处理器迟早将打入智能手机和平板电脑市场,这是一场马拉松比赛,而不是短跑冲刺。   欧德宁称:“在平板电脑和智能手机市场,英特尔目前毫无建树。每个人都想知道我们将如何应对,但赢得这场战争需要时间。”   10多年来,英特尔一直试图将其在PC市场的主导地位普及到手机和其他移动设备市场。但目前还没有任何一款智能手机采用英特尔处理器,苹果iPad和其他厂商的平板电脑也未使用英特尔处理器。但欧德宁表示,计划在2011年展示首款采用英特尔处理器的智能手机。   作为全球最大的PC处理器制造商,英特尔四年前调整了移动处理器开发战略,推出了Atom处理器。对
[手机便携]
小广播
设计资源 培训 开发板 精华推荐

最新单片机文章
何立民专栏 单片机及嵌入式宝典

北京航空航天大学教授,20余年来致力于单片机与嵌入式系统推广工作。

换一换 更多 相关热搜器件
更多往期活动
随便看看

 
EEWorld订阅号

 
EEWorld服务号

 
汽车开发圈

电子工程世界版权所有 京B2-20211791 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号 Copyright © 2005-2024 EEWORLD.com.cn, Inc. All rights reserved