Linux内核编程(三)----------Linux内核的基本概念

        写在前面:充满机遇与挑战的2019年来了,年前由于各个项目的原因,这个系列停滞了好久,新的一年虽然项目也是非常紧张,但还是争取闲暇的时间利用起来,把这个系列咬咬牙写完。任何成功和舒适,都是苦尽甘来,你想要得到,就必须付出;想要成功,就必须努力。只有现在吃了学习的苦,将来才会少吃生活的苦。2019,我们都是追梦人。

      正文:本篇主要介绍Linux内核的基本概念

     1、    物理地址&虚拟地址:
        (1)、地址转换:Linux内核所使用的地址一定是虚拟地址,但是CPU真正最后访问的是物理地址,所以必须有一个转换的过程。
            虚拟地址转换成物理地址接口:static inline phys_addr_t virt_to_phys(const volatile void *x);//                       //arch/arm/include/asm/memory.h
            物理地址转换成虚拟地址接口:static inline void *phys_to_virt(phys_addr_t x);//arch/arm/include/asm/memory.h
        (2)、页表:物理地址到虚拟地址转换,必须通过查一张表格来进行转换,这张表格就是页表。Linux里面最小的内存管理单元是页,一般页的大小是4K,所以页表 的大小就是访问的所有的物理地址除以4K。即如果内存空间大小是4G,则页表的大小是4G/4k = 1M大小。页表是存在内存中的。
            页表初始化:init/main.c
            start_kernel->mm_init->mm_alloc_pgd  //初始化第一级页表  
            
            将驱动设备本身的内存空间映射到主页表中
            arch/arm/include/asm/io.h
            ioremap(cookie,size) //cookie,物理地址,size,大小
            ioremap->_arch_ioremap->arm_ioremap->_arm_ioremap->__arm_ioremap_pfn_caller->ioremap_page_range---分配pgd
            
        (3)、内存的属性:可读、可写、可执行。即每一个页都会有一个属性。物理地址到虚拟地址转换的一个重要的原因是操作系统要实现对内存属性的控制。

        2、Linux内核中的内存管理:
        (1)、内核以页(4K bytes)为单位进行内存管理。
        (2)、内存管理相关的几个API举例:
            alloc_pages(gfp_t gfp_mask, unsigned int order)
            作用:内核分配内存的底层调用,可以分配整页的内存,他分配的内存以页为单位即4K为单位
                gfp_mask:区分内存的条件。
                参数: GFP_NOWAIT:分配内存的过程不允许等待(一般中断里面)。
                           GFP_ATOMIC:原子操作,大致也是不允许等待
                           GFP_NOFS:申请的内存不用于文件操作
                           GFP_KERNEL:申请的内存给内核用
                           GFP_USER:申请的内存给用户用
                           GFP_IOFS:申请的内存给外设用
            order:分配的页的个数,分配2^order个页面。
            kmalloc(size_t size, gfp_t flags)
            作用:内核中常用的分配内存的函数,可以以字节为单位进行分配,分配连续的内存,速度快。

            vmalloc(unsigned long size)
            作用:也是内核中分配内存的函数,他和kmalloc的不同点,vmalloc分配的可以是物理上不连续的内存,效率较低,用于不重要场合。

    3、系统调用:

        用户程序想要调用内核函数的一种方式(API)。通过一个execption,使得一个应用程序陷入内核中执行。
        例如:比如应用程序想要运行另一个程序,可以用exec族函数,exec族函数会产生SWI类型的exception(异常),从而陷入内核,执行内核函数sys_execve->do_execve,从而运行另一个程序。

   4、 内核线程:
        (1)、内核中只有线程,没有进程(或者只有1个进程)。因为所有的内核代码空间只有1份。
        (2)、线程的task_struct,线程运行的核心数据结构,包含内核的所有信息。这个结构体非常庞大,包括进程的优先级(int prio, static_prio, normal_prio;nsigned int rt_priority;)、堆栈信息(void *stack;)、打开的文件句柄信息(struct files_struct *files;)等等。
        (3)、内核线程的调度。内核线程中只有3种调度方式:SCHED_RR(时间片轮转)、SCHED_PRI(优先级)、SCHED_RT(实时)。调度的时机:时钟中断发生、Linux发生内核态和用户态互相切换时、Linux执行信号时。

       5、中断:
        (1)、中断的硬件概念:就是一个外部的电平信号,通过外部电平信号的高低来中断cpu。
        (2)、中断处理的上半部:当发生一个中断时,Linux内核暂时不响应其他硬件中断的处理,这个时间很短,一定时处理关键而迅速完成的程序段。另外,这个程序段一定不能等待其他条件发生。   
        (3)、中断处理的下半部:上半部中来不及处理的比较冗长的程序段;需要等待其他程序运行结果或者需要等待获取其他资源的程序段。  

        6、时钟和定时器管理:
        (1)、时钟的硬件概念:时钟从硬件上讲是一种产生定时中断的电路。
        (2)、RTC和system timer: RTC:实时计数器;system timer:很多情况就是用作为延时和计算相对时间的。
        (3)、tick&&jiffies: tick,时钟中断的周期。jiffies:是一个全局变量,如果是64 bit系统,他就是一个64位的变量,记录了从上电开始所经历的tick数。
       查看cpu的tick:在 linux-3.0.8目录下 打开  .config   文件,找到 CONFIG_HZ=200  这个宏就可以,即tick的周期事1/200s。


              jiffies的定义,是个全局变量:# define jiffies    raid6_jiffies()

      7 、文件系统概述:
        (1)、虚拟文件系统(VFS):是Linux 内核为了屏蔽物理文件系统差异,所产生的一个中间层。linux内核访问实际物理文件系统时的中间层。
            do_mount ->do_new_mount ->do_kern_mount -> vfs_kern_mount -> mount_fs -> root = type->mount(type, flags, name, data);
        (2)、主要的物理文件系统(ext4、yaffs2等):ext4最大特点是有完善的日志系统。yaffs2比较适合在nandflash上部署的文件系统。ubifs和btfs,这两种是比较流行的新的文件系统。

     8、内核中的同步和线程间通信方式:
        (1)、原子操作:不会被打断的基本操作,即一条指令就可以完成的事情,不同的CPU架构不同,例如,i++在有的平台一条指令可以完成,有的平台一条指令不会完成。
        (2)、同步通信方式:linux 内核中有两大类 
                1、自旋锁  spin_lock
                2、信号量 (semaphore)up和down两个函数(up 释放信号量,down 获取信号量)
             上述两者的区别:spin_lock不会引起阻塞,可用在中断上半部, up和down可引起阻塞,不能用在中断上半部
        (3)、异步通信方式:主要有信号(signal)实现(注意信号和信号量是完全不同的东西),例如:进程A向进程B发个信号要求进程B做个事情,一般不要求进程B马上执行。

    

发布了91 篇原创文章 · 获赞 160 · 访问量 19万+

猜你喜欢

转载自blog.csdn.net/weixin_40204595/article/details/87453030