嵌入式开发工程师笔试面试指南-面试题目整理(5)

1 linux中内核空间及用户空间的区别?用户空间与内核通信方式有哪些

区别

权限不同:内核空间具最高权限,可直接访问硬件;用户空间权限受限,操作受内核管控。

功能不同:内核空间负责系统核心管理;用户空间运行普通应用程序。

内存不同:两者内存相互隔离,保证系统稳定。

通信方式

系统调用:用户程序请求内核服务的标准途径。

信号:内核通知用户进程事件。

proc/sysfs 文件系统:用户可读写对应文件与内核交互。

netlink 套接字:常用于网络相关通信。

2 linux中内存划分及如何使用?虚拟地址及物理地址的概念及彼此之间的转化,高端内存概念

内存划分与使用

Linux 将内存划分为内核空间和用户空间。内核空间供内核使用,处理系统关键任务,如进程调度、硬件管理等;用户空间运行普通应用程序。用户程序通过系统调用请求内核分配内存,内核使用伙伴系统和 slab 分配器管理内存。

虚拟地址与物理地址

概念:虚拟地址是程序使用的地址,为每个进程提供独立的地址空间,增强程序的可移植性和安全性;物理地址是内存芯片的实际地址。

转化:通过内存管理单元(MMU)和页表实现。MMU 根据页表将虚拟地址映射为物理地址。

高端内存

物理内存较大时,内核无法直接映射全部内存,超出部分为高端内存。内核需动态映射高端内存,使用临时映射或永久映射机制,映射后才能访问其中数据。

3 Linux中中断的实现机制,tasklet与workaueue的区别及底层实现区别?为什么要区分上半部和下半部

Linux 中断实现机制

硬件产生中断信号,通过中断控制器传递给 CPU。CPU 收到信号后,暂停当前程序,根据中断向量表找到对应的中断服务程序(ISR)入口,执行 ISR。ISR 完成后,CPU 恢复原程序执行。

tasklet 与 workqueue 区别及底层实现

区别:tasklet 运行于软中断上下文,执行快且不允许睡眠;workqueue 运行于内核线程上下文,可睡眠,适合处理耗时任务。

底层实现:tasklet 基于软中断机制,有自己的调度队列,在软中断处理时被调度执行;workqueue 由内核线程实现,将工作项放入队列,内核线程从队列取出执行。

区分上半部和下半部原因

中断发生时,上半部快速响应,完成紧急操作,如应答中断、保存现场。下半部处理耗时任务,避免影响其他中断响应,提高系统实时性和处理效率。

4 Iinux中断的响应执行流程

Linux 中断的响应执行流程如下:

中断发生

硬件设备产生中断信号,如网卡接收到数据,将中断信号发送给中断控制器。中断控制器对信号进行管理和优先级排序,再将处理后的信号传递给 CPU。

中断响应

CPU 检测到中断信号后,暂停当前正在执行的程序,保存现场,包括程序计数器、寄存器等信息,以便后续恢复执行。根据中断向量表找到对应中断服务程序(ISR)的入口地址。

执行上半部

进入 ISR 的上半部,此部分代码执行速度快,完成紧急操作,如应答中断控制器,防止重复触发中断;保存关键数据等。

调度下半部

上半部完成后,若有需要后续处理的任务,会调度下半部执行。下半部可通过 tasklet、工作队列等机制实现,在合适时机处理耗时任务。

恢复现场

中断处理完成后,恢复之前保存的现场,CPU 继续执行被中断的程序。

5 linux中的同步机制?spinlock与信号量的区别

Linux 中的同步机制

Linux 中有多种同步机制,用于解决并发访问共享资源时的数据不一致问题。常见的有自旋锁、信号量、互斥体、读写锁等。这些机制能保证在多进程或多线程环境下,对共享资源的访问是有序的。

spinlock 与信号量的区别

等待方式:spinlock 是忙等待,获取不到锁时,进程会一直循环检查锁的状态,占用 CPU 资源;而信号量获取不到时,进程会进入睡眠状态,让出 CPU。

使用场景:spinlock 适用于锁持有时间短的场景,避免进程频繁睡眠和唤醒的开销;信号量适合锁持有时间长的情况,可让 CPU 处理其他任务。

中断上下文使用:spinlock 可在中断上下文中使用,因为它不会引起睡眠;信号量不能在中断上下文中使用,因为中断处理程序不能睡眠。

6 Linux中RCU原理

RCU(Read-Copy-Update)是 Linux 内核的一种同步机制。其原理是允许多个读操作并发执行,且读操作无需加锁,不影响性能。当有写操作时,先复制一份数据副本进行修改,待所有读操作完成旧数据使用后,再用新副本更新数据并释放旧数据。它通过维护读端临界区和回调机制实现数据同步,适合读多写少场景。

7 Linux设备中字符设备与块设备有什么主要的区别?请分别列举一些实际的设备说出它们是属于哪一类

Linux 设备中字符设备与块设备主要有以下区别,并列举一些实际设备说明:

数据传输方式

字符设备:以字符为单位按顺序进行数据传输,数据的读取和写入是连续的流,就像从文件中逐字符读取或写入一样。

块设备:以块为单位进行数据传输,块的大小通常是固定的,如 512 字节或 4096 字节等,数据的读写可以随机访问不同的块。

访问特点

字符设备:通常用于面向流的设备,数据的访问是顺序的,不支持随机访问,应用程序一般需要按照顺序依次读取或写入数据。

块设备:支持随机访问,应用程序可以直接访问设备上的任意块,而不必按照顺序依次访问。

典型设备

字符设备:如键盘、鼠标、串口设备、打印机等。以键盘为例,用户按下按键时,字符会逐个输入到系统中,系统按顺序接收和处理这些字符。

块设备:常见的有硬盘、固态硬盘、U 盘、光盘等。以硬盘为例,操作系统可以根据需要随机读取或写入硬盘上的任意一个数据块,而不必像字符设备那样顺序访问。

8 设备请简述主设备号和次设备号的用途

主设备号

标识设备类型:用于区分不同种类的设备驱动程序,同一类设备具有相同的主设备号。例如,所有的硬盘设备可能共享一个特定的主设备号,而所有的串口设备有另一个主设备号,系统通过主设备号能快速定位到对应的设备驱动程序。

建立驱动关联:内核利用主设备号来查找和调用相应的设备驱动程序,当设备进行读写等操作时,内核依据主设备号找到对应的驱动入口点,从而实现对设备的控制和操作。

次设备号

区分同类设备:在同一类设备中,用于区分不同的具体设备实例。比如系统中有多个硬盘,每个硬盘通过不同的次设备号来标识,以便系统对它们进行单独的管理和操作,如分别对不同硬盘进行分区、格式化等。

实现设备定制:可以用于指定设备的特定属性或功能变体。例如,某些设备可能有不同的工作模式或配置选项,次设备号可以用来区分这些不同的情况,使驱动程序能够根据次设备号执行不同的操作或提供不同的功能。

9 请简述中断于DMA的区别

中断和 DMA(直接内存访问)是计算机系统中用于数据传输和处理的两种不同机制,它们的区别如下:

数据传输方式:中断方式下,CPU 需不断查询或响应设备中断来传输数据,是由 CPU 控制的;DMA 方式则是由 DMA 控制器直接控制数据在内存和设备间传输,无需 CPU 干预。

应用场景:中断适用于处理少量、随机的数据交互,如键盘输入;DMA 适合大量数据的快速传输,像硬盘与内存间的数据读写。

对 CPU 的影响:中断会频繁打断 CPU 当前工作,影响 CPU 效率;DMA 传输时 CPU 可处理其他任务,大大提高了 CPU 的利用率。

10 中断和轮询哪个效率高?怎样决定是采用中断方式还是采用轮询方式去实现驱动

中断和轮询的效率高低及采用哪种方式实现驱动需根据具体情况判断,以下是相关分析:

效率比较

一般情况下,中断的效率更高。中断是由设备主动发送信号给 CPU,CPU 在接收到中断信号后才会去处理设备相关事务,无需 CPU 不断查询,不会浪费 CPU 时间在无意义的轮询上。而轮询需要 CPU 不断地去检查设备状态,不管设备是否有数据需要处理,在设备无数据时,这种检查是无效的,会占用大量 CPU 资源,导致 CPU 利用率低。

选择依据

设备活动频率:如果设备数据产生频繁且无规律,如键盘输入,适合用中断,可及时响应。若设备活动是周期性且可预测的,如每隔固定时间采集一次传感器数据,轮询可能更合适。

实时性要求:对实时性要求极高的设备,如工业控制中的紧急制动设备,中断能保证快速响应。实时性要求不高,如一些状态监测设备,轮询方式可满足需求。

系统资源情况:若系统资源充足,对 CPU 占用不太敏感,且希望程序逻辑简单,可选择轮询。若系统资源紧张,且有多个设备需要管理,为提高 CPU 利用率,宜采用中断方式。

11 字符型驱动设备你是怎么创建设备文件的,就是/dev/下面的设备文件,供上层应用程序打开使用的文件?写一个中断服务需要注意哪些?如果中断产生之后要做比较多的事情你是怎么做的?

字符型驱动设备创建设备文件

在 Linux 中,可以使用mknod命令手动创建设备文件,也可以在驱动程序中使用udev或sysfs机制自动创建设备文件。以udev为例,驱动程序通常会在module_init函数中使用alloc_chrdev_region分配主设备号和次设备号,然后使用cdev_init和cdev_add注册字符设备驱动。当设备插入或驱动加载时,udev会根据内核提供的信息在/dev目录下自动创建设备文件。

写中断服务注意事项

快速执行:中断服务程序应尽可能快速地执行,避免长时间占用 CPU,影响其他中断的响应。

避免阻塞:不要在中断服务程序中使用可能会阻塞的操作,如等待信号量、进行大量的内存分配等。

保存和恢复现场:需要保存和恢复中断发生时的 CPU 寄存器等现场信息,确保中断返回后程序能正确继续执行。

中断屏蔽与使能:在适当的时候屏蔽和使能中断,防止中断嵌套导致问题。

中断产生后处理较多事情的做法

如果中断产生后要做比较多的事情,通常采用中断下半部机制。将一些不是非常紧急的任务放到下半部处理,这样可以让中断服务程序快速执行完毕,及时响应其他中断。下半部可以使用工作队列、软中断或 tasklet 等机制来实现。例如,使用工作队列时,在中断服务程序中只是简单地将工作添加到工作队列中,然后由内核在合适的时机调度工作队列中的任务来执行具体的处理操作。

12 linux中内存划分及如何使用?虚拟地址及物理地址的概念及彼此之间的转化,高端内存概念?

Linux 内存划分及使用

Linux 内存通常分为内核空间和用户空间。32 位系统中,一般低 3GB 为用户空间,供应用程序使用,高 1GB 为内核空间,用于内核代码和数据。

内核通过内存管理模块分配和管理物理内存,如伙伴系统用于管理物理内存的分配和回收,slab 分配器用于为内核对象分配小内存。用户空间的应用通过系统调用如malloc等申请和使用内存。

虚拟地址与物理地址

虚拟地址:是应用程序使用的地址,每个进程都有自己独立的虚拟地址空间,它让进程以为自己独占系统资源,实现了进程间的隔离和保护。

物理地址:是内存芯片上存储单元的实际地址,用于内存控制器对物理内存的访问。

地址转化:通过内存管理单元(MMU)和页表机制实现。虚拟地址被分为页号和页内偏移,页表存储虚拟页到物理页的映射关系,MMU 根据页表将虚拟地址转换为物理地址。

高端内存

指 32 位系统中,内核无法直接映射到线性地址空间的物理内存区域,通常是高于 896MB 的内存。

因为 32 位系统内核空间只有 1GB,除去内核代码等占用,剩余可直接映射的内存有限,高端内存的引入增加了系统可使用的物理内存空间,内核访问高端内存时需要通过特殊的映射机制。

13 linux中中断的实现机制,tasklet与workaueue的区别及底层实现区别?为什么要区分上半部和下半部?

Linux 中断的实现机制

当硬件设备需要 CPU 处理时,会发送一个电信号给 CPU 的中断引脚,CPU 在执行完当前指令后,会检查中断引脚是否有信号。若有,CPU 会根据中断向量表找到对应的中断服务程序(ISR)入口地址,然后保存当前的寄存器等现场信息,跳转到 ISR 执行。执行完 ISR 后,再恢复现场,继续执行原来被中断的程序。

tasklet 与 workqueue 的区别及底层实现区别

区别

执行上下文:tasklet 在中断上下文执行,不能睡眠;workqueue 在进程上下文执行,可以睡眠。

执行时机:tasklet 通常在中断返回前或软中断处理时很快被执行;workqueue 会在系统调度合适的内核线程时执行,执行时间相对不那么确定。

底层实现区别:tasklet 基于软中断实现,通过tasklet_struct结构体管理,有自己的执行函数和数据。workqueue 基于内核线程实现,通过work_struct结构体表示工作单元,加入到workqueue_struct结构体表示的工作队列中,由内核线程来执行队列中的工作。

区分上半部和下半部的原因

提高响应速度:上半部快速处理紧急的硬件相关操作,如接收硬件数据、应答硬件等,然后快速返回,以便及时响应其他中断。

分离任务:将不紧急、可以延迟处理的任务放到下半部,如数据处理、更新用户空间等操作,这样可以使中断处理更高效,也能让系统更好地并发处理其他事务,避免因中断处理时间过长影响系统整体性能。

14 ARM下U-boot给Kemel传参数

在 ARM 架构下,U-Boot 给 Kernel 传参数主要通过以下方式:

U-Boot 通常会将参数存放在一个特定的内存区域,这个区域一般被称为设备树(Device Tree)或者 ATAGs(ARM Linux Atoms)。设备树是一种描述硬件资源信息的数据结构,它以树形结构描述了系统中的各种硬件设备及其属性等信息。U-Boot 会根据硬件配置生成相应的设备树,并将其地址通过特定的寄存器或者约定的内存位置告知 Kernel。对于一些较老的系统或不使用设备树的情况,可能会使用 ATAGs 来传递参数,ATAGs 是一系列以特定格式组织的结构体,包含了诸如内存大小、启动参数等信息,U-Boot 会将 ATAGs 链的首地址传递给 Kernel,Kernel 启动时会根据这个地址来解析参数。

在 U-Boot 的代码中,通常会有相关的函数来设置和传递这些参数,例如setup_start_tag等函数用于构建 ATAGs,而对于设备树,则会通过dt_fixup_memory_banks等函数来处理和传递设备树信息。

15 判断大端小端模式

联合类型判断法

使用联合体union的特性,其所有成员共享同一块内存空间。

指针判断法

通过指针操作访问整数的低地址字节

16 大小端模式转换

大小端模式转换通常用于处理不同字节序系统间的数据交互。下面给出两种常见数据类型的转换方法:

16 位数据转换

#include <stdint.h>

uint16_t swap16(uint16_t val) {
    return (val << 8) | (val >> 8);
}

32 位数据转换

#include <stdint.h>

uint32_t swap32(uint32_t val) {
    return ((val & 0xFF000000) >> 24) |
           ((val & 0x00FF0000) >> 8) |
           ((val & 0x0000FF00) << 8) |
           ((val & 0x000000FF) << 24);
}

17 为什么会产生僵尸进程?

僵尸进程是指子进程已经结束运行,但父进程没有调用wait或waitpid系统调用来获取子进程的退出状态等信息,导致子进程的进程描述符等资源无法被释放,从而处于一种特殊的状态。以下是僵尸进程产生的常见原因:

父进程未回收:父进程可能因为设计缺陷、逻辑错误或忙于其他任务等原因,没有及时调用wait或waitpid来等待子进程结束并回收其资源。

父进程异常终止:父进程在子进程之前意外崩溃或被强制杀死,而没有机会回收子进程资源,子进程就会成为僵尸进程。

信号处理不当:父进程在处理信号等操作时,可能忽略了对子进程状态的检查和回收,导致子进程结束后无法被正确处理。

18 如何清理僵尸进程?

以下是几种清理僵尸进程的方法:

等待子进程结束

父进程调用wait()、waitpid()等函数,获取子进程的退出状态,释放其占用的系统资源。如在父进程代码里添加合适的wait逻辑。

重启父进程

若父进程已无法正常处理子进程退出,可尝试重启父进程。新的父进程会重新管理子进程,能避免僵尸进程堆积。

终止父进程

若父进程存在严重问题,可使用kill命令终止父进程。之后,子进程会被init进程接管,init会自动清理僵尸进程。

19 NAND驱动的probe流程

在 Linux 系统中,NAND 驱动的 probe 流程通常如下:

设备注册阶段:驱动程序在初始化时会通过platform_driver_register等函数向系统注册一个平台设备驱动,其中包含了驱动的各种信息和操作函数指针。

匹配阶段:当系统启动或插入新的 NAND 设备时,设备和驱动会根据设备树中的信息或其他匹配机制进行匹配。例如,通过比较设备的名称、ID 等信息来确定是否是该驱动所支持的设备。

probe 函数调用:如果匹配成功,系统会调用驱动的probe函数。在probe函数中,首先会进行硬件资源的初始化,如设置 NAND 控制器的寄存器,配置引脚等。

检测 NAND 设备:接着通过发送特定的命令和读取响应来检测 NAND 芯片的类型、容量等参数。例如,通过读取设备的 ID 来确定具体的 NAND 型号。

初始化 MTD 设备:根据检测到的信息,初始化 MTD(Memory Technology Device)设备结构体,设置其操作函数指针,如read、write、erase等函数,以便上层文件系统能够通过这些接口来访问 NAND 设备。

注册 MTD 设备:最后,将初始化好的 MTD 设备通过mtd_device_register函数注册到系统中,使系统能够识别和使用该 NAND 设备。

20 哈佛结构&冯诺依曼结构

哈佛结构和冯诺依曼结构是计算机体系结构中的两种重要类型,以下是它们的详细介绍:

概念

冯诺依曼结构:也称普林斯顿结构,是一种将程序指令存储器和数据存储器合并在一起的存储器结构。程序指令和数据共用一套总线,CPU 通过同一组总线来访问程序和数据。

哈佛结构:是一种将程序指令存储和数据存储分开的存储器结构。它有独立的程序总线和数据总线,使得 CPU 可以同时对程序和数据进行访问。

特点

冯诺依曼结构

指令和数据共享总线:使得硬件结构相对简单,成本较低。但在同一时间内,CPU 只能进行取指令或者存取数据操作,限制了数据处理速度。

程序和数据统一编址:可以使程序和数据存放在同一存储空间,易于实现程序的自我修改等操作。

哈佛结构

独立的总线:程序总线和数据总线相互独立,允许同时进行指令读取和数据访问,提高了数据吞吐率,更适合于实时性要求较高的信号处理等应用。

程序和数据分开存储:可以对程序空间和数据空间采取不同的保护机制,增强了系统的稳定性和安全性。

#嵌入式#

该专栏面向嵌入式开发工程师,包括C语言、C++,操作系统,ARM架构、RTOS、Linux基础、Linux驱动、Linux系统移植、计算机网络、数据结构与算法、5篇面试题目、HR面试常见问题汇总和嵌入式面试简历模板等18篇文章。超全的嵌入式软件工程师笔试面试题目和高频知识点总结!招聘so easy。

全部评论
如果大家觉得可以帮助到自己,麻烦点赞、评论和订阅哦😀
1 回复 分享
发布于 昨天 21:14 安徽
点赞 回复 分享
发布于 今天 10:26 江苏
点赞 回复 分享
发布于 今天 11:36 江苏

相关推荐

评论
2
1
分享

创作者周榜

更多
正在热议
更多
牛客网
牛客企业服务