嵌入式高频八股:操作系统篇
启动流程
为什么两次初始化DDR
- 第一次是BOOTLOADER初始化DDR,使其从不可用到可用,保证可以正常的引导和加载操作系统,会将UBOOT的BL1从FLASH中拷贝到DDR中执行。
- 第二次是LINUX启动过程中对DDR进行更加细致的初始化,并且将DDR的内存配置与内核的内存管理需求匹配。
UBOOT启动流程
【ARM-LINUX开发】U-BOOT启动过程--详细版的完全分析 - ZHANGPYI - 博客园 (CNBLOGS.COM)
中断
中断类型
- 中断
- 可屏蔽
- 不可屏蔽
- 异常
- 陷阱(TRAP) 系统调用、信号
- 故障(FAULT) 缺页异常
- 错误
GIC中三种中断
- SPI 共享外设中断
- PPI 私有外设中断
- SGI 软件生成中断
SGI通过软件向GIC的SGIR寄存器写值来产生中断,GIC根据内容分发给特定核心
ISR中断服务函数
ISR(INTERRUPT SERVICE ROUTINE),即中断服务程序,是处理器在响应硬件中断时执行的特殊函数。它用于处理硬件事件,并在完成后返回正常的程序执行流。ISR是嵌入式系统和实时操作系统中的关键组件。
- 快速执行
- 不使用阻塞操作
- 避免使用全局变量
- 嵌套中断
软中断
LINUX中断(INTERRUPT)子系统之五:软中断(SOFTIRQ)-阿里云开发者社区 (ALIYUN.COM)
软中断与软件中断
用途 | LINUX内核提供的延时处理机制 分离较为复杂的工作推迟处理 |
系统调用、异常处理、虚拟化环境通信 |
触发方式 | 硬中断或者其他部分触发 | 特定指令触发 |
执行环境 | 特定调度时机 | 中断上下文 |
硬件怎么告诉驱动信息来了
中断。继续回答中断的流程。一般是通过一个硬件引脚,发送给GIC控制器,然后捕获这个中断信号,GIC管理优先级排序和消息分发给对应的CPU,然后CPU会进入中断处理函数处理,这个函数一般是驱动注册的回调函数去区里,然后清除掉中断,CPU恢复继续去执行
中断初始化时需要设备树信息,是不是需要去解析它
是的。 在嵌入式系统中,设备树通常用于描述硬件配置,如中断控制器、GPIO、中断号等。当一个设备驱动初始化时,它会从设备树中提取相关的硬件信息,这包括中断相关的属性。具体步骤大致如下:
- 设备树节点描述:设备树中每个设备节点都可能包含中断信息,通常使用属性如
INTERRUPTS
或INTERRUPT-PARENT
。中断控制器也通过设备树节点描述其类型和配置。 - 解析设备树:内核启动时,内核设备树解析器会根据设备树的内容建立硬件信息,特别是中断控制器的信息。然后设备驱动可以通过特定的 API 来读取和解析设备树中的中断号和触发类型。
- 调用 DT 解析 API:LINUX 内核提供了相关 API,比如
OF_IRQ_GET()
、IRQ_OF_PARSE_AND_MAP()
等,这些函数帮助驱动从设备树中提取和映射中断号。驱动程序会调用这些 API 获取设备树中的中断信息。 - 中断注册:在解析出设备树中的中断信息后,驱动程序会使用
REQUEST_IRQ()
等 API 注册中断处理函数。
中断中为什么不可以睡眠?
面试官:为什么在中断里不能 SLEEP | LINUX 内核 - 知乎 (ZHIHU.COM)
- 中断是在中断上下文中,与任何的进程上下文无关
- 内核代码里有大量的 CRITICAL SECTION (临界区),如果想要支持 CALL SCHEDULER 的话,那么所有的 CRITICAL SECTION 都必须得禁用中断,否则硬件中断一旦来临系统就会出现 RACE CONDITION,接下来大概率是死锁。但是这样的中断响应延迟就很大。
内存管理
内存碎片的类型
- 外部碎片:内存有足够的内存,但是由于空闲空间被分成多个不连续小块,无法满足分配大的内存空间
- 内部碎片:分配的内存块比实际需求大的多,多出来的部分无法使用
内存碎片产生的原因、有哪些场景产生、怎么解决
产生原因:
- 外部碎片:内存有足够的内存,但是由于空闲空间被分成多个不连续小块,无法满足分配大的内存空间
- 内部碎片:分配的内存块比实际需求大的多,多出来的部分无法使用
场景:
- 频繁的动态分配和释放内存
- 操作系统分配内存可能产生碎片
- 虚拟内存系统将物理内存映射到虚拟地址空间时
解决方式:
- 优化算法
- 首次适配(FIRST FIT):找到第一个能满足要求的空闲块进行分配。
- 最佳适配(BEST FIT):找到最接近所需大小的空闲块进行分配,减少外部碎片。
- 最坏适配(WORST FIT):找到最大的空闲块进行分配,尝试保留大块空间以减少未来的外部碎片。
- 伙伴算法
- SLAB算法
- 垃圾回收
- 内存压缩:适当的时候进行整理
- 内存池
伙伴算法的优缺点
优点
- 分配速度快,分割和合并效率简单高效
- 减少外部碎片
- 内存对齐 缺点
- 依旧存在内部碎片
- 内存利用率不高(内部碎片的问题)
- 复杂性
环形缓冲区怎么判断空、满
环形缓冲区有BEGIN END两个指针,当
- 空 BEGIN=END
- 满 BEGIN->NEXT=END
内存泄漏
总的来说一句话,分配了内存没有释放。
- NEW 没有FREE
- 循环引用,计数器无法归零
- 丢失指针
解决办法:
- 分配后释放
- 智能指针
- 避免循环引用
工具:
- ADDRESSSANITIZER
- VALGRIND
内核空间与用户空间之间的内存拷贝
通过COPY_TO_USER()
与COPY_FROM_USER
,在拷贝的时候会进行地址的检测,是否指向有效的用户空间内存区域,以及确保访问不会越界。然后操作系统内核会使用 CPU 的特权模式来访问用户空间的内存地址。因为进入内核的时候页表不会改变,依旧用的是用户进程的页表(所有进程的内核空间映射是同一个位置,用户态进入内核态不需要切换页表)。这些地址通过 MMU 进行转换,映射到物理内存,然后内核通过物理内存地址进行读写操作。由于用户空间的内存地址可能是虚拟地址,内核需要通过页表进行转换,找到对应的物理地址。这个过程是由硬件 MMU 和操作系统联合完成的。
总结:通过特定函数,内核以特权模式直接向用户空间虚拟地址指向的物理地址进行拷贝。
应用层随便写个地址,内核是怎么检测出异常的
进程在创建的时候会先将分配好自己所需要的虚拟地址空间,但是此时并没有对实际的物理地址分配映射,后续需要的时候才会分配,所以可以区分下面两种来对检测异常做解释:
- 缺页异常:发现需要访问的地址在已经分配的虚拟地址空间内,但是没有映射到物理地址,就会触发缺页异常,然后分配物理地址做出映射,放到页表中方便后续使用。
- 段错误:发现需要访问的地址超出了虚拟地址的空间,或者超过了堆栈的范围,或者是访问的页面权限不符,就会认为是一个错误地址。
IOMMU的作用与意义
作用:
- 地址转换:
- IOMMU 为 I/O 设备提供虚拟地址空间支持,类似于 CPU 使用 MMU 来管理进程的虚拟地址空间。IOMMU 将设备发出的虚拟地址转换为物理地址,使设备可以访问系统内存,而不需要知道物理内存的实际布局。
- 这种地址转换还允许设备在被重新配置时,不需要修改其所使用的内存地址,只需修改 IOMMU 的映射即可。
- 内存保护:
- IOMMU 提供了一个安全层,通过限制设备可以访问的内存区域,防止设备意外或恶意地访问其他进程或内核空间的内存。
- 这种保护对防止 DMA(DIRECT MEMORY ACCESS,直接内存访问)攻击特别重要,因为攻击者可能试图利用 DMA 设备直接访问内存,从而绕过操作系统的安全机制。
- 设备隔离:
- 在虚拟化环境中,IOMMU 可以帮助实现虚拟机对物理设备的隔离。它允许虚拟机使用物理设备的虚拟化版本,同时确保这些设备只能访问分配给它们的内存区域。
- 这种隔离对于确保虚拟机之间的安全性至关重要,因为它防止了一个虚拟机能够通过设备访问其他虚拟机的内存。
- 提高系统性能:
- 在多核和多设备的复杂系统中,IOMMU 可以优化内存访问路径,使得 I/O 操作更高效,减少 CPU 处理内存访问的负担。
- 通过 IOMMU,设备可以直接访问系统内存,而无需通过中介或额外的内存拷贝,这种直接访问(DMA)可以显著提高数据传输速率。
意义:
- 安全性增强:
- IOMMU 是现代计算机系统安全架构中的关键组成部分。它通过防止设备对不安全内存区域的访问,大大提高了系统的安全性。尤其是在
剩余60%内容,订阅专栏后可继续查看/也可单篇购买
1. 自我介绍:高通、Oppo(sp)、vivo(sp)、小米(ssp)、荣耀(26k*12+80k)、华子(报批中)、美团、韶音、经纬恒润、乐鑫、中兴、TP 2. 内容: 1.嵌入式学习的资料和路径 2.所有面试的题目和解答(持续更新)、对评论的快速解答 3.各种碎碎念 3.整理不易,buy me coffee☕️,为了回馈牛客和各个粉丝,文章都会先试读几天,热度过了再收录~