内存管理初始化源码2:setup_arch
PFN相关宏说明:
/* kernel/include/linux/pfn.h */ PFN : Page Frame Number(物理页帧)
/* * PFN_ALIGN:返回地址x所在那一页帧的下一页帧的起始地址。 * 例如:PFN_ALIGN(0x00000800) = 0x00001000 ; PFN_ALIGN(0x00001800) = 0x00002000; * 理解:假如我们认为一页大小是0x0f,那么当前地址是0x08,如何通过0x08获得0x10呢? 0x08 + (0x10 - 1) = 0x17, 然后再把低位抹掉,不就刚好是10. * 问题:这样做有一个问题,如果x=0x0,那么返回的是0x0,而不是0x10,这是为什么呢?*/#define PFN_ALIGN(x) (((unsigned long)(x) + (PAGE_SIZE - 1)) & PAGE_MASK) /* * PFN_UP:获取地址x所在物理页帧的的后一个PFN值,即x如果属于page 0, 则返回1. * 问题:如果 x = 0x0, 那么返回的不是1,而是0;如果 x = 0x00001000,返回的是1,而不是2.为什么?*/#define PFN_UP(x) (((x) + PAGE_SIZE-1) >> PAGE_SHIFT) /* * PFN_DOWN:获取地址x所在物理页帧的前一个PFN值,即如果x属于page 1,则返回0.*/#define PFN_DOWN(x) ((x) >> PAGE_SHIFT)
/* * PFN_PHYS:返回PFN值为x时,对应的物理页帧的起始地址*/#define PFN_PHYS(x) ((phys_addr_t)(x) << PAGE_SHIFT) 关于上述问题,其实如果看看它的实际应用场景就会明白的。要记住:PFN是一个从0开始的页帧编号
打印结果记录:
initrd_start = 0x81a0000, initrd_end = 0x81b2e720
我们继续看 start_kernel—>setup_arch—>arch_mem_init—>bootmem_init。
/* kernel/arch/mips/kernel/setup.c */ static void __init bootmem_init(void) {unsigned long reserved_end;unsigned long mapstart = ~0UL;unsigned long bootmap_size;int i;/** Init any data related to initrd. It's a nop if INITRD is* not selected. Once that done we can determine the low bound* of usable memory.*/ /* * 初始化所有和initrd相关的数据。如果没有INITRD,这将是一个空操作。一旦该操作完成,我们就可以确定可用内存的边界。 */
// 计算需要为initrd保留的内存区域,那么剩余的内存就是可用内存 reserved_end = max(init_initrd(),(unsigned long) PFN_UP(__pa_symbol(&_end))); // reserved_end = max(0x1b2f, 0x936) = 0x1b2f /** Redo reserved_end because there is no need to reserve so much memory(about 20MB).*/reserved_end = (unsigned long) PFN_UP(__pa_symbol(&_end)); // reserved_end = 0x936 = 2358(PFN) /* * 上述步骤中得 PFN_UP(__pa_symbol(&end)) 不太懂,没有继续深入,而且上述步骤计算reserved_end做的一些事也是不太理解!! *//** max_low_pfn is not a number of pages. The number of pages* of the system is given by 'max_low_pfn - min_low_pfn'. * 系统物理页帧总数 = max_low_pfn - min_low_pfn*/min_low_pfn = ~0UL;max_low_pfn = 0;/** Find the highest page frame number we have available.*/ /* * 寻找最大可用PFN。 * 代码很简单,记录下我们的打印,助于分析: * memory: 0e000000 @ 00000000 (usable) * memory:10000000 @ 30000000 (usable) * start = 0, end = 53744 * start = 196608, end = 262144 * mapstart = 2358 */for (i = 0; i < boot_mem_map.nr_map; i++) {unsigned long start, end;if (boot_mem_map.map[i].type != BOOT_MEM_RAM)continue;start = PFN_UP(boot_mem_map.map[i].addr);end = PFN_DOWN(boot_mem_map.map[i].addr+ boot_mem_map.map[i].size);if (end > max_low_pfn)max_low_pfn = end;if (start < min_low_pfn)min_low_pfn = start;if (end <= reserved_end)continue;if (start >= mapstart)continue;mapstart = max(reserved_end, start);}if (min_low_pfn >= max_low_pfn)panic("Incorrect memory mapping !!!");if (min_low_pfn > ARCH_PFN_OFFSET) {pr_info("Wasting %lu bytes for tracking %lu unused pages\n",(min_low_pfn - ARCH_PFN_OFFSET) * sizeof(struct page),min_low_pfn - ARCH_PFN_OFFSET);} else if (min_low_pfn < ARCH_PFN_OFFSET) {pr_info("%lu free pages won't be used\n",ARCH_PFN_OFFSET - min_low_pfn);}min_low_pfn = ARCH_PFN_OFFSET; // 就是0/** Determine low and high memory ranges*/ /* HIGHMEM_START:定义在kernel/arch/include/asm/mach-generic/spaces.h 对于32位系统, #define HIGHMEM_START _AC(0x20000000, UL) 【就是512M,从512M开始的物理地址认为是高端内存】 经过下边的计算:highstart_pfn = PFN_DOWN(HIGHMEM_START) = 131072, hightend_pfd = 262144 min_low_pfn = 0, max_low_pfn = 131072 */max_pfn = max_low_pfn;if (max_low_pfn > PFN_DOWN(HIGHMEM_START)) { #ifdef CONFIG_HIGHMEMhighstart_pfn = PFN_DOWN(HIGHMEM_START);highend_pfn = max_low_pfn; #endifmax_low_pfn = PFN_DOWN(HIGHMEM_START);}/** Initialize the boot-time allocator with low memory only. * 在系统启动过程中,内存管理尚未初始化,但内核需要分配内存 以创建各种数据结构,bootmem分配器用于在启动阶段早起的内存分配。 * 所以,init_bootmem_node计算 bootmem allocator 所需内存大小,该部分内存是作为 reserved memory。*/bootmap_size = init_bootmem_node(NODE_DATA(0), mapstart,min_low_pfn, max_low_pfn);for (i = 0; i < boot_mem_map.nr_map; i++) {unsigned long start, end;start = PFN_UP(boot_mem_map.map[i].addr);end = PFN_DOWN(boot_mem_map.map[i].addr+ boot_mem_map.map[i].size);if (start <= min_low_pfn)start = min_low_pfn;if (start >= end)continue;#ifndef CONFIG_HIGHMEMif (end > max_low_pfn)end = max_low_pfn;/** ... finally, is the area going away?*/if (end <= start)continue; #endif// start 和 end 没有发生改变: // start = 0, end = 57344 // start = 196608, end = 262144add_active_range(0, start, end); // 记录物理内存的PFN信息}/** Register fully available low RAM pages with the bootmem allocator. * 注册所有的可用低端内存给bootmem allocator【bootmem allocator可以操作低端内存】*/for (i = 0; i < boot_mem_map.nr_map; i++) {unsigned long start, end, size;/** Reserve usable memory.*/if (boot_mem_map.map[i].type != BOOT_MEM_RAM)continue;start = PFN_UP(boot_mem_map.map[i].addr);end = PFN_DOWN(boot_mem_map.map[i].addr+ boot_mem_map.map[i].size);/** We are rounding up the start address of usable memory* and at the end of the usable range downwards.*/if (start >= max_low_pfn)continue;if (start < reserved_end)start = reserved_end;if (end > max_low_pfn)end = max_low_pfn;/** ... finally, is the area going away?*/if (end <= start)continue; /* start = 2358, end = 53744 */size = end - start;/* Register lowmem ranges 【完成注册】*/free_bootmem(PFN_PHYS(start), size << PAGE_SHIFT);memory_present(0, start, end);}/** Reserve the bootmap memory.【保留bootmap memory,mapstart = 2358, PFN_PHYS(mapstart) = 0x936000, bootmap_size = 16384Byte】*/reserve_bootmem(PFN_PHYS(mapstart), bootmap_size, BOOTMEM_DEFAULT);/** Reserve initrd memory if needed.【为initrd保留内存】 Initial ramdisk at:0x81a00000 (1238816 bytes)*/finalize_initrd(); }
2. init_initrd
在 kernel/init/do_mounts_initrd.c中定义了变量:
unsigned long initrd_start, initrd_end;
在arch_mem_init —> parse_early_param 中,不仅调用了early_parse_mem函数,同时也调用了:rd_start_early和rd_size_early。
这两个函数就是解析 command line 中指定的 initrd 的内存信息,代码我就贴了,调用这两个函数的结果就是:
initrd_start = 0x81a00000 initrd_end = 0x81b2e720 /** command line : console=ttyS3,115200n8 mem=224M@0x0 mem=256M@0x30000000 ip=off root=/dev/ram0 rw rdinit=/init rd_start=0x81A00000 rd_size=0x0012E720 */
此时, arch_mem_init—>bootmem_init—>init_initrd:
/* it returns the next free pfn after initrd */ static unsigned long __init init_initrd(void) {unsigned long end;/** Board specific code or command line parser should have* already set up initrd_start and initrd_end. In these cases* perfom sanity checks and use them if all looks good.*/if (!initrd_start || initrd_end <= initrd_start)goto disable;if (initrd_start & ~PAGE_MASK) {pr_err("initrd start must be page aligned\n");goto disable;}if (initrd_start < PAGE_OFFSET) {pr_err("initrd start < PAGE_OFFSET\n");goto disable;}/** Sanitize initrd addresses. For example firmware* can't guess if they need to pass them through* 64-bits values if the kernel has been built in pure* 32-bit. We need also to switch from KSEG0 to XKPHYS* addresses now, so the code can now safely use __pa().*/end = __pa(initrd_end);initrd_end = (unsigned long)__va(end);initrd_start = (unsigned long)__va(__pa(initrd_start));ROOT_DEV = Root_RAM0;return PFN_UP(end); disable:initrd_start = 0;initrd_end = 0;return 0; }
转载于:https://www.cnblogs.com/ronnydm/p/5889834.html
内存管理初始化源码2:setup_arch相关推荐
- Linux创建页表内存代码,Linux内存管理的源码实现
399 void mem_init(l start_mem, l end_mem) 400 { 401 int i; 402 403 high_memory = end_mem; 404 for (i ...
- linux 内存管理slab源码,Linux内核源代码情景分析-内存管理之slab-回收
图 1 我们看到空闲slab块占用的若干页面,不会自己释放:我们是通过kmem_cache_reap和kmem_cache_shrink来回收的.他们的区别是: 1.我们先看kmem_cache_sh ...
- C#共享内存实例 附源码
原文 C#共享内存实例 附源码 网上有C#共享内存类,不过功能太简单了,并且写内存每次都从开头写.故对此进行了改进,并做了个小例子,供需要的人参考. 主要改进点: 通过利用共享内存的一部分空间(以下称 ...
- Quartz的Scheduler初始化源码分析
2019独角兽企业重金招聘Python工程师标准>>> Quartz的使用:http://donald-draper.iteye.com/blog/2321886 Quartz的S ...
- SpringMVC源码探究软件六合网站制作(一)----初始化源码
随着软件 , 开发技术的持续发展,框架技术层出不穷.还是那句话,任何框架技术都是对基础技术的封装.所以,真正要学好用好一个框架,研究其源码都是最直接最有效的途径. 随着Spring技术体系的强势发展, ...
- Spring IoC容器初始化源码(1)—容器初始化入口以及setConfigLocations设置容器配置信息【一万字】
基于最新Spring 5.x,对于基于XML的Spring IoC容器初始化过程中的setConfigLocations设置容器配置信息方法的源码进行了详细分析,最后给出了比较详细的方法调用时序图 ...
- spring4.1.8初始化源码学习三部曲之三:AbstractApplicationContext.refresh方法
本章是<spring4.1.8初始化源码学习三部曲>系列的终篇,重点是学习AbstractApplicationContext类的refresh()方法: 原文地址:https://blo ...
- 阿加内存管理 初始化(八) 至kswapd_init
至此,内存初始化部分已看完,遗留问题: 1.对于unicore或者mips的页表建立都很清楚,但是对于ARM我不清楚: 初始化部分涉及的页表映射建立,我都以unicore架构为准,ARM的页表映射从原 ...
- 流量卡物联网卡管理平台源码|PHP管理系统源码
简介: 市面流量卡物联网卡管理平台源码|PHP管理系统源码: 市面上很火的流量卡项目,可以用这套平台系统来管理,实现自定义套餐名以及流量卡运营,充值收款. 即时返佣功能都有,内附搭建教程.自行研究! ...
最新文章
- IDEA搭建Maven Web(SSM)项目(一)——创建项目
- A、B、C、D四个字母,能组成多少个互不相同且无重复三位组合
- 但凡网络工程师会这个技能,也不至于天天抱怨工资低
- 关于ubuntu下无线网卡经常连不上网络的问题
- 记一次查深圳磨房百公里徒步照片历程
- OSPF区域类型及详解
- 不能是underfined.xxx
- 计算机网络中速率(date rate)和带宽的区别
- for循环输出菱形星星
- 微信小程序自定义导航栏(带汉堡包菜单)
- 七大步教你征服丈母娘
- springCloud——ribbon和zuul
- Kitty用HTML和css咋做,使用 CSS3 绘制 Hello Kitty
- 互融云供应链金融系统4.0 来了!系统又增哪些亮点?
- telnet 使用教程(新手篇)及问题集锦
- 电脑添加了无线之后要怎么连接服务器,电脑如何连接打印机,无线打印机怎么连接无线路由器...
- python怎么实现检验_Python数据正态性检验实现过程
- 关于出现Table 'mysql.mysql' doesn't exist的解决办法
- 功率预测发展趋势之中长期预报
- 关于安卓苹果手机安装证书抓https的关键步骤
热门文章
- 2022数据血缘关系详解
- python语法糖是什么_Python语法糖Syntactic Sugar
- scipy.stats.norm函数
- 程序算法艺术与实践:基础知识之函数的渐近的界
- 简析一下程序化交易系统在期货交易中的作用
- 删除Office Word (Excel)中Recent Document最近文档中本地和online打开文件路径已经不存在的文件记录
- 前端提高篇(八十六):jQuery的class属性操作addClass()与removeClass()、hasClass()、toggleClass()
- Singularity的安装
- Hystrix vs Sentinel
- Eclipse使用时遇到一直在Validating中的解决办法