OK6410A 开发板 (八) 11 linux-5.11 OK6410A start_kernel 打印角度 第一阶段 mem

本文深入剖析了Linux内核的内存管理初始化过程,包括页表的创建、memblock分配、buddy和slab初始化、虚拟内存布局以及vmalloc区域的设置。详细描述了setup_arch函数中的内存相关操作,如页表初始化、memblock的内存预留和释放、buddy分配器的建立以及slab缓存的配置。通过对不同阶段的内存管理组件的初始化,展示了内核如何逐步建立起完整的内存管理体系。
摘要由CSDN通过智能技术生成

该阶段完成了
1. 根据 memblock 的 reserved 成员  reserve 不需要填充的页表 // reserve_bootmem_region

2. 通过 在 全物理内存内 互补 memblock 的 reserved,得到未使用的物理内存,填充需要填充的页表 // __free_memory_core

3. 至此 , buddy 初始化完成

4.(内存地址,内存大小,申请块大小)填充 kmalloc_caches[type([0-1])][idx([6-d])]

5. 至此 , slab 初始化完成

6. 将 在vmalloc区间的 已经使用的虚拟内存地址A(主要是io设备) 注册到 vmap_area_root

7. 通过 在 全虚拟内存(非vmalloc区间)内 互补 A , 得到虚拟地址空间,注册到 free_vmap_area_root

8. 至此 , vmalloc 初始化完成

// 现在已经不打印 虚拟内存布局 了 
// 请查看 1c31d4e96b8c205fe3aa8e73e930a0ccbf4b9a2b

其实 setup_arch 中也有 关于 mem 的部分

setup_arch 中 与mem 相关的部分

2. 匹配 板级 mdesc , 并解析 atags(包括core cmdline mem)
5. 初始化 各种类型的 描述符表
6. 添加 各种(kernel/initrd/设备树/atags/设备树中预留的/)预留的内存到 memblock
7. 对 即将存储页表的地址 清0
8. 针对 多项内容(lowmem/设备树/vectors/各项设备)填充页表
10. 申请内存,用于存储 很多个struct  page 
11. 初始化所有的 struct page


可以这么说 , setup_arch  中完成了
	1. 虚拟页表的创建(lowmem/设备树/vectors/各项设备)
	2. memblock 的初始化 // 在 setup_arch 的末尾,已经可以 通过 memblock_alloc 来 申请内存了
	3. buddy初始化的第一部分 // 所有低端内存的 struct page 已经准备好了

在这篇文章中,主要关注下面的函数
	page_address_init
		// null
	setup_arch
		// 之前已经讨论过
	build_all_zonelists
		// 打印信息
		// Built 1 zonelists, mobility grouping on.  Total pages: 65024
	mm_init
		// 打印信息
		// mem auto-init: stack:off, heap alloc:off, heap free:off
		// Memory: 243936K/262144K available (5120K kernel code, 6569K rwdata, 732K rodata, 1024K init, 2134K bss, 18208K reserved, 0K cma-reserved)
		// SLUB: HWalign=64, Order=0-3, MinObjects=0, CPUs=1, Nodes=1

  • build_all_zonelists
build_all_zonelists
	build_all_zonelists_init
		__build_all_zonelists
			for_each_online_node(nid) build_zonelists(pgdat);
				zonerefs = pgdat->node_zonelists[ZONELIST_FALLBACK]._zonerefs;
				nr_zones = build_zonerefs_node(pgdat, zonerefs);
					zone = pgdat->node_zones + zone_type;
					zoneref_set_zone(zone, &zonerefs[nr_zones++]);
						zoneref->zone = zone;
						zoneref->zone_idx = zone_idx(zone);
				zonerefs += nr_zones;
				
		for_each_possible_cpu(cpu) pageset_init(&per_cpu(boot_pageset, cpu));
		mminit_verify_zonelist
		cpuset_init_current_mems_allowed
	vm_total_pages = nr_free_zone_pages(gfp_zone(GFP_HIGHUSER_MOVABLE)); // fe00
	page_group_by_mobility_disabled = 0;
  • mm_init
mm_init
	page_ext_init_flatmem
		// null
	init_mem_debugging_and_hardening
		// TODO
	report_meminit
		// pr_info
	mem_init
		set_max_mapnr(pfn_to_page(max_pfn) - mem_map);
			max_mapnr = pfn_to_page(max_pfn) - mem_map;
		/* this will put all unused low memory onto the freelists */
		memblock_free_all
			free_unused_memmap // 稀疏内存相关,释放不存在的地址
				free_memmap
			reset_all_zones_managed_pages
			pages = free_low_memory_core_early
			
				// reserve all the struct page
				for_each_reserved_mem_range(i, &start, &end) reserve_bootmem_region(start, end); // reserve_bootmem_region 执行了 16次
					for (; start_pfn < end_pfn; start_pfn++) 
						init_reserved_page(start_pfn);
						INIT_LIST_HEAD(&page->lru);
						__SetPageReserved(page);
				
					/*
					// 这 16 个 是 memblock 中的 reserved 成员
						为 kernel/页表/struct page/vectors   预留的
						还有 io map/request_standard_resources 过程中申请的内存
					reserve_bootmem_region // 16次,之所以是16次,是因为之前调用了 memblock_alloc 16次
						start_pfn:50004,end_pfn:50008 // 标记这段地址已经被使用,用作页表
							page:cfdf5080
							page:cfdf50a0
							page:cfdf50c0
							page:cfdf50e0
						start_pfn:50100,end_pfn:51081 // 标记这段地址已经被使用,用作 kernel中的 (__pa(KERNEL_START), KERNEL_END - KERNEL_START)
							page:cfdf7000
							...
							page:cfe16000
						start_pfn:5fdbc,end_pfn:5fdf4
							page:cfff0780
							...
							page:cfff0e60
						start_pfn:5fdf5,end_pfn:5fffc // 标记这段地址已经被使用,用作 struct page
							page:cfff0ea0
							...
							page:cfff4f60
						start_pfn:5fffc,end_pfn:5fffd
							page:cfff4f80
						start_pfn:5fffc,end_pfn:5fffd
							page:cfff4f80
						start_pfn:5fffc,end_pfn:5fffd
							page:cfff4f80
						start_pfn:5fffc,end_pfn:5fffd
							page:cfff4f80
						start_pfn:5fffc,end_pfn:5fffd
							page:cfff4f80
						start_pfn:5fffc,end_pfn:5fffd
							page:cfff4f80
						start_pfn:5fffc,end_pfn:5fffd
							page:cfff4f80
						start_pfn:5fffc,end_pfn:5fffd
							page:cfff4f80
						start_pfn:5fffc,end_pfn:5fffd
							page:cfff4f80
						start_pfn:5fffc,end_pfn:5fffd
							page:cfff4f80
						start_pfn:5fffc,end_pfn:5fffd
							page:cfff4f80
						start_pfn:5fffc,end_pfn:60000 // 标记这段被 vectors 和 其他等 占用
							page:cfff4f80
							...
							page:cfff4fe0
					
					*/
				
				// free mem	
				for_each_free_mem_range __free_memory_core(start, end);
					__free_pages_memory(start_pfn, end_pfn); // __free_pages_memory 执行了 4次
						memblock_free_pages(pfn_to_page(start), start, order);
							__free_pages_core
								__free_pages_ok
									free_one_page
										__free_one_page
											add_to_free_list(page, zone, order, migratetype);
											
	/*
		__free_pages_memory 执行了4次
		// 之所以是4次,是因为 总的内存 减去  memblock_alloc 的内存 ,只剩下4块连续的 free 内存
		
		start_pfn:50000,end_pfn:50004							// 标记这段内存没被使用
			pfn_to_page(start):cfdf5000, start:50000, order:2
		start_pfn:50008,end_pfn:50100							// 标记这段内存没被使用,虽然这段是属于kernel的,但是不属于 kernel 的 (__pa(KERNEL_START), KERNEL_END - KERNEL_START)
			pfn_to_page(start):cfdf5100, start:50008, order:3
			pfn_to_page(start):cfdf5200, start:50010, order:4
			pfn_to_page(start):cfdf5400, start:50020, order:5
			pfn_to_page(start):cfdf5800, start:50040, order:6
			pfn_to_page(start):cfdf6000, start:50080, order:7
		start_pfn:51081,end_pfn:5fdbc
			pfn_to_page(start):cfe16020, start:51081, order:0
			pfn_to_page(start):cfe16040, start:51082, order:1
			pfn_to_page(start):cfe16080, start:51084, order:2
			pfn_to_page(start):cfe16100, start:51088, order:3
			pfn_to_page(start):cfe16200, start:51090, order:4
			pfn_to_page(start):cfe16400, start:510a0, order:5
			pfn_to_page(start):cfe16800, start:510c0, order:6
			pfn_to_page(start):cfe17000, start:51100, order:8
			pfn_to_page(start):cfe19000, start:51200, order:9
			pfn_to_page(start):cfe1d000, start:51400, order:a
			pfn_to_page(start):cfe25000, start:51800, order:a
			pfn_to_page(start):cfe2d000, start:51c00, order:a
			pfn_to_page(start):cfe35000, start:52000, order:a
			pfn_to_page(start):cfe3d000, start:52400, order:a
			pfn_to_page(start):cfe45000, start:52800, order:a
			pfn_to_page(start):cfe4d000, start:52c00, order:a
			pfn_to_page(start):cfe55000, start:53000, order:a
			pfn_to_page(start):cfe5d000, start:53400, order:a
			pfn_to_page(start):cfe65000, start:53800, order:a
			pfn_to_page(start):cfe6d000, start:53c00, order:a
			pfn_to_page(start):cfe75000, start:54000, order:a
			pfn_to_page(start):cfe7d000, start:54400, order:a
			pfn_to_page(start):cfe85000, start:54800, order:a
			pfn_to_page(start):cfe8d000, start:54c00, order:a
			pfn_to_page(start):cfe95000, start:55000, order:a
			pfn_to_page(start):cfe9d000, start:55400, order:a
			pfn_to_page(start):cfea5000, start:55800, order:a
			pfn_to_page(start):cfead000, start:55c00, order:a
			pfn_to_page(start):cfeb5000, start:56000, order:a
			pfn_to_page(start):cfebd000, start:56400, order:a
			pfn_to_page(start):cfec5000, start:56800, order:a
			pfn_to_page(start):cfecd000, start:56c00, order:a
			pfn_to_page(start):cfed5000, start:57000, order:a
			pfn_to_page(start):cfedd000, start:57400, order:a
			pfn_to_page(start):cfee5000, start:57800, order:a
			pfn_to_page(start):cfeed000, start:57c00, order:a
			pfn_to_page(start):cfef5000, start:58000, order:a
			pfn_to_page(start):cfefd000, start:58400, order:a
			pfn_to_page(start):cff05000, start:58800, order:a
			pfn_to_page(start):cff0d000, start:58c00, order:a
			pfn_to_page(start):cff15000, start:59000, order:a
			pfn_to_page(start):cff1d000, start:59400, order:a
			pfn_to_page(start):cff25000, start:59800, order:a
			pfn_to_page(start):cff2d000, start:59c00, order:a
			pfn_to_page(start):cff35000, start:5a000, order:a
			pfn_to_page(start):cff3d000, start:5a400, order:a
			pfn_to_page(start):cff45000, start:5a800, order:a
			pfn_to_page(start):cff4d000, start:5ac00, order:a
			pfn_to_page(start):cff55000, start:5b000, order:a
			pfn_to_page(start):cff5d000, start:5b400, order:a
			pfn_to_page(start):cff65000, start:5b800, order:a
			pfn_to_page(start):cff6d000, start:5bc00, order:a
			pfn_to_page(start):cff75000, start:5c000, order:a
			pfn_to_page(start):cff7d000, start:5c400, order:a
			pfn_to_page(start):cff85000, start:5c800, order:a
			pfn_to_page(start):cff8d000, start:5cc00, order:a
			pfn_to_page(start):cff95000, start:5d000, order:a
			pfn_to_page(start):cff9d000, start:5d400, order:a
			pfn_to_page(start):cffa5000, start:5d800, order:a
			pfn_to_page(start):cffad000, start:5dc00, order:a
			pfn_to_page(start):cffb5000, start:5e000, order:a
			pfn_to_page(start):cffbd000, start:5e400, order:a
			pfn_to_page(start):cffc5000, start:5e800, order:a
			pfn_to_page(start):cffcd000, start:5ec00, order:a
			pfn_to_page(start):cffd5000, start:5f000, order:a
			pfn_to_page(start):cffdd000, start:5f400, order:a
			pfn_to_page(start):cffe5000, start:5f800, order:a
			pfn_to_page(start):cffed000, start:5fc00, order:8
			pfn_to_page(start):cffef000, start:5fd00, order:7
			pfn_to_page(start):cfff0000, start:5fd80, order:5
			pfn_to_page(start):cfff0400, start:5fda0, order:4
			pfn_to_page(start):cfff0600, start:5fdb0, order:3
			pfn_to_page(start):cfff0700, start:5fdb8, order:2
		start_pfn:5fdf4,end_pfn:5fdf5							// 标记这段内存没被使用
			pfn_to_page(start):cfff0e80, start:5fdf4, order:0
	*/


/*
至此,50000000 - 60000000 已经被 struct page 记录完毕

50000 000 - 50004 000 : free // 0x5000 0100 应该有 atags ,但是memblock 没预留这段内存,因为 atags 已经解析完了,没用了
50004 000 - 50008 000 : reserved // 页表/段表
50008 000 - 50100 000 : free 
50100 000 - 51081 000 : reserved // kernel 的 (__pa(KERNEL_START), KERNEL_END - KERNEL_START)
51081 000 - 5fdbc 000 : free
5fdbc 000 - 5fdf4 000 : reserved // 过程中 memblock_alloc 过的内存
5fdf4 000 - 5fdf5 000 : free 
5fdf5 000 - 5fffc 000 : reserved // struct page
5fffc 000 - 60000 000 : reserved // vectors等
*/


			totalram_pages_add(pages);
				_totalram_pages = _totalram_pages + pages ; // _totalram_pages 初始化为0
		free_highpages
			// null
		mem_init_print_info
			pr_info("Memory: %luK/%luK available (%luK kernel code
		

		
		// 这个过程初始化 好的 内存管理器 是 buddy
		// 怎么向 buddy 申请内存
		// alloc_pages/alloc_page

	page_ext_init_flatmem_late
		// null
	kmem_cache_init
		// 打印信息
		// SLUB: HWalign=64, Order=0-3, MinObjects=0, CPUs=1, Nodes=1
		// A1. 初始化局部变量 boot_kmem_cache 的成员
		// A2. bootstrap(&boot_kmem_cache) , 并以返回值 作为 全局变量 struct kmem_cache *kmem_cache; 的 值
		// B1. 初始化局部变量 boot_kmem_cache_node 的成员
		// B2. bootstrap(&boot_kmem_cache_node) , 并以返回值 作为 全局变量 struct kmem_cache *kmem_cache_node; 的 值
		// C . 用 create_kmalloc_caches 填充 kmalloc_caches[type([0-1])][idx([6-d])]
		// create_kmalloc_caches-> new_kmalloc_cache -> create_kmalloc_cache
		// 填充的值 为 create_kmalloc_cache 的返回值,该值为struct kmem_cache
		// struct kmem_cache 中有内存仓库的 内存大小,内存仓库的地址,可申请内存块的大小
		// 内存仓库用来存储 多个 内存块 , 每个块为  X  ,且该 内存仓库的 可申请块大小 就为 X
		// X 与 idx 相关 , 具体去看 kmalloc_info 数组(mm/slab_common.c)
		// idx : 6 , X : 0x40
		// idx : 7 , X : 0x80
		// idx : 8 , X : 0xc0
		// idx : 9 , X : 0x10
		// idx : a , X : 0x200
		// idx : b , X : 0x400
		// idx : c , X : 0x1000
		// idx : d , X : 0x2000
		
		// 消费者 如何  向 kmem_cache 申请内存
		// kmalloc
		
		// 这个过程初始化完成的内存管理器叫 slab
		
	kmemleak_init
		// null
	pgtable_init
		ptlock_cache_init
			// null
		pgtable_cache_init
			// null
	debug_objects_mem_init
		// null
	vmalloc_init
		// 针对所有的虚拟内存 1 - ffffffff
	
		// vmap_area_cachep = 0xc1401600;
		// /* Import existing vmlist entries. */
			/*
			insert_vmap_area
			A : start_kernel-> setup_arch-> paging_init-> smdk6410_map_io-> s3c64xx_init_io-> iotable_init-> add_static_vm_early
			// A 设置了11个
			B : start_kernel-> setup_arch-> paging_init-> tcm_init-> iotable_init-> add_static_vm_early
			// B 设置了2个
			start:f6000000,end:f6004000 // A 设置的
			start:f6010000,end:f6014000 // A 设置的
			start:f6100000,end:f6101000 // A 设置的
			start:f6200000,end:f6201000 // A 设置的
			start:f6300000,end:f6304000 // A 设置的
			start:f6400000,end:f6401000 // A 设置的
			start:f6500000,end:f6501000 // A 设置的
			start:f6600000,end:f6601000 // A 设置的
			start:f6700000,end:f6701000 // A 设置的
			start:f7005000,end:f7006000 // A 设置的
			start:f7100000,end:f7104000 // A 设置的
			start:fffe0000,end:fffe4000 // B 设置的
			start:fffe8000,end:fffec000 // B 设置的
			*/			
		// vmap_init_free_space
			// The KVA space
			/*
			insert_vmap_area_augment
			start:1,end:f6000000
			start:f6004000,end:f6010000
			start:f6014000,end:f6100000
			start:f6101000,end:f6200000
			start:f6201000,end:f6300000
			start:f6304000,end:f6400000
			start:f6401000,end:f6500000
			start:f6501000,end:f6600000
			start:f6601000,end:f6700000
			start:f6701000,end:f7005000
			start:f7006000,end:f7100000
			start:f7104000,end:fffe0000
			start:fffe4000,end:fffe8000
			
			*/
			
			// 

			/*
			start:fffec000,end:ffffffff
			*/

		// 消费者调用的是什么 API
		// vmalloc
	ioremap_huge_init
		// null
	init_espfix_bsp
		// null
	pti_init
		// null
	

其他
create_kmalloc_cache
	kmem_cache_zalloc
		kmem_cache_alloc
			slab_alloc
				slab_alloc_node
					__slab_alloc
						___slab_alloc
							get_freelist
								freelist = page->freelist;
	create_boot_cache
		__kmem_cache_create
			kmem_cache_open
			sysfs_slab_add

insert_vmap_area
	find_va_links
	link_va
kmalloc 和 vmalloc 的区别
	vmalloc 返回值 在 vmalloc区间内

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值