Qemu调试内核环境搭建

近期学习了一下Qemu的使用,发现Qemu功能很强大,提供的能力较多,同时也为使用增加的难度,尤其是那堆参数。同样是由于那堆参数,可以构造出很复杂的模拟环境来。不过构造模拟环境不是这次的重点,这次重点是如何快速搭建一个可以调试内核的环境来。

此次使用的系统环境是Ubuntu 20.04版本。通过sudo su –切换到root用户上进行操作,从安全角度来说不推荐,可以基于普通用户加sudo去操作需要特[……]

阅读全文

Linux设备驱动框架剖析

前提概要

      众所周知,计算机的核心是CPULinux系统就是运行在CPU之上的。但是仅仅有CPU是不够的,还需要有内存、磁盘、键盘、鼠标、显示器等各种各样的设备。Linux系统运行起来就需要将各种设备接入到计算机当中,那么他们是怎么和CPU联系在一起的呢?

通过上图我们可以看到,CPU出来后F[……]

阅读全文

OpenSSL与证书的那些事儿

    前面分析过加解密、证书与安全通信之间的关联关系(参考博文《漫谈从加解密到信任证书构成的安全通信》),现在换个角度来剖析证书的制作与其本质。我们先构建一个CA环境,生成CA密钥、制作CA证书请求、自签名等,然后通过自建的CA来签发用户证书。

准备工作

通过命令查询openssl的环境信息,主要是确认openssl的配置路径信息OPENSSLDIR

[……]

阅读全文

漫谈从加解密到信任证书构成的安全通信

加密(Encryption就是通过某种方法将可以被理解的数据信息隐藏起来并生成不可被理解的数据信息。可理解的数据信息通常称之为明文(Plain Text,而隐藏了明文的不可被理解的数据信息被称之为密文(Cipher。至于解密(Decryption,则恰好相反,它是将密文转变为明文的过程,将被隐藏的信息从不可被理解的数据信息中还原出来。

加密解密的历史甚为久远,早在古代就出现了采用字符替代或者字符移[……]

阅读全文

【Linux内存源码分析】vmalloc不连续内存管理(1)

伙伴管理算法初衷是解决外部碎片问题,而slab算法则是用于解决内部碎片问题,但是内存使用的得不合理终究会产生碎片。碎片问题产生后,申请大块连续内存将可能持续失败,但是实际上内存的空闲空间却是足够的。这时候就引入了不连续页面管理算法,即我们常用的vmalloc申请分配的内存空间,它主要是用于将不连续的页面,通过内存映射到连续的虚拟地址空间中,提供给申请者使用,由此实现内存的高利用。

按照分析管理,从该管理算法的初始化入手。[……]

阅读全文

【Linux内存源码分析】内存泄漏检测kmemleak示例

分析完kmemleak实现后,照常实验一下,以确定功能正常。

kmemcheck一样,该功能需要在内核开启的情况下才能够使用。主要的配置项有:CONFIG_DEBUG_KERNELCONFIG_HAVE_DEBUG_KMEMLEAKCONFIG_DEBUG_KMEMLEAK,以及配置信息记录条数的CONFIG_DEBUG_KMEMLEAK_EARLY_LOG_SIZE,通常情况下配置数量的可以不必修改,但是针对自启[……]

阅读全文

【Linux内存源码分析】内存泄漏检测kmemleak分析

kmemleak的工作原理很简单,主要是对kmalloc()vmalloc()kmem_cache_alloc()等接口分配的内存地址空间进行跟踪,通过对其地址、空间大小、分配调用栈等信息添加到PRIO搜索树中进行管理。当有匹配的内存释放操作时,将会把跟踪的信息从kmemleak管理中移除。

通过内存扫描(包括对保存的寄存器值),如果发现某块内存在没有任何一个指针指向其起始地址或者其空间范围,那么该内存将会被判定为孤[……]

阅读全文

【Linux内存源码分析】内存破坏检测kmemcheck示例

前面分析了kmemcheck的实现,那么现在就针对其功能进行试验,鉴于kmemcheck支持KMEMCHECK_SHADOW_UNALLOCATED、KMEMCHECK_SHADOW_UNINITIALIZEDKMEMCHECK_SHADOW_FREED的检测且检测上报信息大同小异,本文中的实验主要针对于未初始化的内存进行。

如果需要使能kmemcheck,需要进行一系列的内核参数设置,具体的配置项可以参考内核源码Do[……]

阅读全文

【Linux内存源码分析】内存破坏检测kmemcheck分析

kmemcheck和kmemleaklinux2.6.31版本开始对外提供的内核内存管理方面的两个检测工具,最初仅支持x86环境,时至今日已经能够支持arm环境了。其中kmemcheck主要是用于内核内存破坏检测,而kmemleak则是用于内核内存泄露检测。本文主要分析kmemcheck的实现,至于kmemleak下一篇文章再详细介绍。

为什么要有kmemcheck?古人云:人非圣贤孰能无过,程序员也会犯错,但是[……]

阅读全文

【Linux内存源码分析】SLUB分配算法(2)

先由slub分配算法初始化进入分析。

回到mm_init()函数中,在调用mem_init()初始化伙伴管理算法后,紧接着调用的kmem_cache_init()便是slub分配算法的入口。其中该函数在/mm目录下有三处实现slab.cslob.cslub.c,表示不同算法下其初始化各异,分析slub分配算法则主要分析slub.c的实现。

该函数具体实现:

【file:/mm/sl[......]

阅读全文

【Linux内存源码分析】SLUB分配算法(1)

前面主要分析了以页为最小单位进行内存分配的伙伴管理算法,这对于内核对内存的管理比较简单,同时较大程度上避免了内存碎片的问题。而实际上对内存的申请却不是每次都申请一个页面的,通常是不规则的,大小不一的,并且远小于一个内存页面的大小,此外更可能会频繁地申请释放这些内存。

明显每次分配小于一个页面的都统一分配一个页面的空间是过于浪费且不切实际的,因此必须充分利用未被使用的空闲空间,同时也要避免过多地访问操作页面分配。基于该问题[……]

阅读全文

【Linux内存源码分析】内存溢出保护机制(OOM)

Linux系统内存管理中存在着一个称之为OOM killerOut-Of-Memory killer)的机制,该机制主要用于内存监控,监控进程的内存使用量,当系统的内存耗尽时,其将根据算法选择性地kill了部分进程。本文分析的内存溢出保护机制,也就是OOM killer机制了。

回到伙伴管理算法中涉及的一函数__alloc_pages_nodemask(),其里面调用的__alloc_pages_slowpath()并[……]

阅读全文

【Linux内存源码分析】连续内存分配器(CMA)

根据git的合入记录,CMAContiguous Memory Allocator,连续内存分配器)是在内核3.5的版本引入,由三星的工程师开发实现的,用于DMA映射框架下提升连续大块内存的申请。

其实现主要是在系统引导时获取内存,并将内存设置为MIGRATE_CMA迁移类型,然后再将内存归还给系统。内核分配内存时,在CMA管理内存中仅允许申请可移动类型内存页面(movable pages),例如DMA映射时不使用的页[……]

阅读全文

【Linux内存源码分析】页面迁移

页面迁移其实是伙伴管理算法中的一部分,鉴于其特殊性,特地另行分析。它是2007年的时候,2.6.24内核版本开发时,新增碎片减少策略(the fragmentation reduction strategy)所引入的。该策略也称之为反碎片技术(anti-gragmentation)。

根据《深入linux内核架构》的描述,反碎片的由来是因为Linux内存管理长期存在一个问题:系统启动并长期运行后,物理内存将会产生很多碎片[……]

阅读全文

【Linux内存源码分析】伙伴管理算法(5)

前面已经分析了伙伴管理算法的释放实现,接着分析一下伙伴管理算法的内存申请实现。

       伙伴管理算法内存申请和释放的入口一样,其实并没有很清楚的界限表示这个函数是入口,而那个不是,所以例行从稍微偏上一点的地方作为入口分析。于是选择了alloc_pages()宏定义作为分析切入口:

【file:/include/linux/gfp.h】
#define[......]

阅读全文

【Linux内存源码分析】伙伴管理算法(3)

前面分析了伙伴管理算法的初始化,在切入分析代码实现之前,例行先分析一下其实现原理。

伙伴管理算法(也称之为Buddy算法),该算法将所有空闲的页面分组划分为MAX_ORDER个页面块链表进行管理,其中MAX_ORDER定义:

【file:/include/linux/mmzone.h】
#ifndef CONFIG_FORCE_MAX_ZONEORDER
#define MAX_ORDER 11[......]

阅读全文

【Linux内存源码分析】伙伴管理算法(1)

前面分析了memblock算法、内核页表的建立、内存管理框架的构建,这些都是x86处理的setup_arch()函数里面初始化的,因地制宜,具有明显处理器的特征。而start_kernel()接下来的初始化则是linux通用的内存管理算法框架了。

build_all_zonelists()用来初始化内存分配器使用的存储节点中的管理区链表,是为内存管理算法(伙伴管理算法)做准备工作的。具体实现:

[……]

阅读全文

【Linux内存源码分析】构建内存管理框架(5)

前面已经分析了内存管理框架的构建实现过程,有部分内容未完全呈现出来,这里主要做个补充。

如下图,这是前面已经看到过的linux物理内存管理框架的层次关系。

现着重分析一下各个管理结构体的成员功能作用。

【file:/include/linux/mmzone.h】
typedef struct pglist_data {
	struct zone node_[......]

阅读全文

【Linux内存源码分析】构建内存管理框架(4)

虽说前文分析内存管理框架构建的实现,提到了find_zone_movable_pfns_for_nodes(),这里不准备复述什么,仅针对required_movablecorerequired_kernelcore做一个补充。

required_movablecore为例,代码中没有很清晰地表明该值从何而来,仅有一处cmdline_parse_movablecore()疑似赋值的实现:

【fi[......]

阅读全文

【Linux内存源码分析】构建内存管理框架(2)

前面构建内存管理框架,已经将内存管理node节点设置完毕,接下来将是管理区和页面管理的构建。此处代码实现主要在于setup_arch()下的一处钩子:x86_init.paging.pagetable_init()。据前面分析可知x86_init结构体内该钩子实际上挂接的是native_pagetable_init()函数。

native_pagetable_init()

【file:/[......]

阅读全文

【Linux内存源码分析】构建内存管理框架(1)

传统的计算机结构中,整个物理内存都是一条线上的,CPU访问整个内存空间所需要的时间都是相同的。这种内存结构被称之为UMAUniform Memory Architecture,一致存储结构)。但是随着计算机的发展,一些新型的服务器结构中,尤其是多CPU的情况下,物理内存空间的访问就难以控制所需的时间相同了。在多CPU的环境下,系统只有一条总线,有多个CPU都链接到上面,而且每个CPU都有自己本地的物理内存空间,但是也可以通过总线去访[……]

阅读全文

【Linux内存源码分析】建立内核页表(1)

前面已经分析过了Intel的内存映射和linux的基本使用情况,已知head_32.S仅是建立临时页表,内核还是要建立内核页表,做到全面映射的。下面就基于RAM大于896MB,而小于4GB ,且CONFIG_HIGHMEM配置了高端内存的环境情况进行分析。

建立内核页表前奏,了解两个很关键的变量:

max_pfn:最大物理内存页面帧号;

max_low_pfn:低端内存区(直接映[……]

阅读全文

【Linux内存源码分析】系统启动阶段的memblock算法(2)

结束完memblock算法初始化前的准备工作,回到memblock算法初始化及其算法实现上面。memblock是一个很简单的算法。

memblock算法的实现是,它将所有状态都保存在一个全局变量__initdata_memblock中,算法的初始化以及内存的申请释放都是在将内存块的状态做变更。那么从数据结构入手,__initdata_memblock是一个memblock结构体。其结构体定义:

[……]

阅读全文

【Linux内存源码分析】系统启动阶段的memblock算法(1)

memblock算法是linux内核初始化阶段的一个内存分配器(它取代了原来的bootmem算法),实现较为简单。负责page allocator初始化之前的内存管理和分配请求。

分析memblock算法,可以从几点入手:

1、 memblock算法初始化;

2、 memblock算法管理内存的申请和释放;

memblock算法前的准备:

[……]

阅读全文

【Linux内存源码分析】X86内存映射小结(2)

本文主要总结一下Intelx86架构处理器所支持各式内存映射情况。

实模式

实模式下,没有什么内存映射的概念,逻辑地址简单地转换一下就是物理地址。

实模式下的逻辑地址表现形式为[BaseOffset](即[基地址:偏移量],虽然Base类似于保护模式下的段选择符,但是实模式下,它仅表示基地址,无任何的段选择作用),逻辑地址转换物理地址的方式为:

(Base &l[……]

阅读全文

【Linux内存源码分析】X86内存映射小结(1)

前面分析了linux内核如何开启保护模式和启用段页映射模式,也都分析了段式映射和段页式映射的一个概况。不过前面的分析只是侧重地讲解了x86 32位环境4Kbytes页面大小的情况,但是实际上x86可支持的分页映射模式远不止于此。所以特地总结一下。

这里先基于保护模式下Intel IA-32架构处理器非PAE4kbytes页面映射的环境分析一下内存映射的整个过程,后面再分析x86环境说支持的映[……]

阅读全文

【Linux内存源码分析】开启分页管理

前面的初探内存保护模式里面,Linux最初进入保护模式,仅仅是一种纯段式的内存映射模式,而且也未起到很明显的保护作用,明显这不是linux内存管理的最终模式。Linux是不使用段保护的,使用的是页保护,所以它还需要开启分页管理。

分页说简单也简单,就是通过页全局目录找到页表接着通过页表找到页面,诸如此类的查找映射方式。但是Intel支持有4k2M4M等不同的内存页面大小,不同的页面大小其映射方式又各有差[……]

阅读全文

【Linux内存源码分析】初探保护模式(2)

接下来,看看linux首次进入的保护模式的内存映射方式,然后再看一下linux是如何实现保护模式的进入,进入前做了什么准备和设置。

还是借用Intel文档中的图来说明这个保护模式的保护功能:

根据不同的段寄存器内容查找到对应的段描述符,描述符指明了此时的环境的可以通过段访问到内存基地址、空间大小和访问权限。访问权限则点明了哪些内存可读、哪些内存可写。[……]

阅读全文

【Linux内存源码分析】初探保护模式(1)

既然都说是分析x86环境的linux系统内存管理,如果不分析一下x86那绕来绕去的内存映射机制,个人感觉等于什么都没分析。其实x86的内存映射机制,说复杂也不复杂,说简单也不简单,简单点说x86内存映射莫过于就两个映射:段式映射和页式映射。其中页式映射是基于段式映射的基础上而形成的,那就意味着可以是:纯段式映射和段页式映射。这些都是简单的,而且映射的结构图在各式各样介绍内存管理的书或者文章上比比皆是。但看点复杂的,GDT[……]

阅读全文

【Linux内存源码分析】内存布局探测

近期深入学习linux内核,先从内存管理下手吧,考虑到老版本的内核分析文章已经较多,于是找了一个较新的LTS内核版本尝试自行分析,这里选择了linux 3.14版本,环境主要是x86-32bit

Linux系统的内存管理是一个很复杂的工程,它不仅仅是物理内存管理,同时包括虚拟内存管理、内存交换和回收等,还有管理中的各式各样的算法。这也就表明了它的分析方法很多,因为切入点很多,这里分析内存管理采用了自底[……]

阅读全文

Bochs调试linux内核环境搭建笔记(3)

近期不小心把系统弄崩了,重装了系统,使用了ubuntu 14.04,顺便准备研究Grub 2.0引导linux的方式,发现制作bochs引导镜像着实不容易,倒也不是操作困难,而是grub命令变更比较大,一时半会还不熟,折腾了好久才算是弄好。特此留下笔记以备后忘。

环境信息:

Ubuntu 14.04
Grub 2.02

1、创建img镜像文件
root@Jean-vm:/home/jeanleo/bochs# dd if=[……]

阅读全文

Bochs调试linux内核环境搭建笔记(2)

此文主要是记录了一下,基于grub 0.97等老版本做Bochs镜像的操作流程,以备后用。该文与前一篇博文总体上面就细节上稍微有些许差异,制作镜像的整体步骤相同。原本有前一篇博文就已经够了,但是个人在研究Linux内核启动的过程中,有部分细节不太清晰,后来发现是GRUB发生了变化的缘故。grub 0.97及之前的版本可以称之为GRUB Legacy,大约2002年左右,Yoshinori K. Okuji在PUPA重写了GRUB,使它更清晰[……]

阅读全文

linux机器启动过程

机器启动到linux初始化是一个比较复杂并且细节性较强的过程,大部分的实现都是由于历史遗留问题以及各种协议约定而来的,衔接性比较强,而且比较难跟踪,毕竟不是C语言那么简单,一个函数调用一个函数,整个脉络比较清晰明了。

这里主要是以linux-3.2.55版本内核为基础,将整个系统的初始化流程梳理了一下。

进入正文:

A、 自摁下电源开关后,是由主板自动初始化处理器信息的,将CS、DS、ES、SS置为0xffff,而PC置为[……]

阅读全文

VMware下CentOS 6编译内核

环境信息:
VMware下安装的CentOS 6.2
VMware Workstation 9.0.0
Linux version 2.6.32-220.el6.i686

环境准备:
下载linux内核源码:http://www.kernel.org
下载的源码版本:linux-2.6.34.14

编译操作:
1)解压源码,习惯性地解压到了/usr/src下面,实际上任意位置都无妨。
tar -xvf linux-[……]

阅读全文