1.什么是嵌入式?
2.字符设备和块设备的区别?
3.进程与程序,进程与线程的区别
4.嵌入式的移植过程
5..守护进程的编写步骤
6.网络的Socket交互过程
7.TCP 三次握手和终止连接的4次握手过程
1)介绍一下你在华清做的这个项目?您在里面负责哪一块? 2)你用的是什么CPU?是什么样的内核? 3)说说嵌入式LINUX移植的过程? 4)字符设备和块设备有什么不同? 5)ARM有几种CPU模式,分别是什么? 6)列举几种文件系统,分别说说他们的优缺点。 7)说说摄像头的视频采集过程
8)如果要提升视频流的流畅度,可以怎么做? 9)按键处理用了CPU哪个中断?
10)BOA和APPACHE有什么区别,你为什么选择XX? 11)嵌入式LINUX 2.6和2.4有什么区别?
以下问答大部分是个人总结,仅供参考,你可以添加合适的自己的理解 1.什么是嵌入式?
A: 嵌入式系统本身是一个相对模糊的定义。目前嵌入式系统已经渗透到我们生活中的每个角落,工业、服务业、消费电子……,而恰恰由于这种范围的扩大,使得“嵌入式系统”更加难于明确定义。以下是几种常见表达方式:
1.执行专用功能并被内部计算机控制的设备或者系统。嵌入式系统不能使用通用型计算机,而且运行的是固化的软件,用术语表示就是固件(firmware),终端用户很难或者不可能改变固件。
2.凡是专用的、小型或者微型的计算机系统都是嵌入式系统,比如MP3, 手机,高清电视 3.比较传神和从技术人员角度来看,嵌入式系统是以应用为中心,以计算机技术为基础,并且软硬件可裁剪,适用于应用系统对功能、可靠性、成本、体积、功耗有严格要求的专用计算机系统。
2.字符设备和块设备的区别?
A: 1.字符设备和块设备、网络设备是一个并列的概念
2字符设备按照字符流的方式被有序访问,块设备以块为单位;二者根本区别在于字符设备只能顺序被读写,块设备可以随机访问
3. Linux为块设备和字符设备提供了两套机制。字符设备实现的比较简单,内核例程和用户态API一一对应,用户层的read函数直接对应了内核中的read例程,这种映射关系由字符设备的file_operations维护。块设备接口相对于字符设备复杂,read、write API没有直接到块设备层, 而是通过IO请求的方式通过OS的IO请求队列实现。内核管理块设备要比管理字符设备细致得多,内核对块设备的管理却提供一个专门的提供服务的子系统。块设备对执行性能的要求很高;,LINUX内核开发者门一直致力于优化块设备的驱动。 3.进程与程序的区别和联系
A:
1.程序是一组指令的集合,它是静态的实体,没有执行的含义。进程程序的执行过程,是一个动态的实体,有自己的生命周期,包括产生、运行、消亡的过程。除此之外,进程还有并发性和交往性。简单地说,进程是程序的一部分,程序运行的时候会产生进程。
2.所涉及到的介质不同,程序保存在存储介质,比如FLASH,硬盘等中,进程运行在RAM中
3.内容不完全相同,程序有数据段,代码段,调试信息等,进程执行时候,有代码段,数据段,以及堆栈
线程和进程的区别:
A:
1、线程是进程的一部分,所以线程有的时候被称为是轻权进程或者轻量级进程。
2、一个没有线程的进程是可以被看作单线程的,如果一个进程内拥有多个进程,进程的执行过程不是一条线(线程)的,而是多条线(线程)共同完成的。
3、系统在运行的时候会为每个进程分配不同的内存区域,但是不会为线程分配内存(线程所使用的资源是它所属的进程的资源),线程组只能共享资源。也就是 说,出了CPU之外(线程在运行的时候要占用CPU资源),计算机内部的软硬件资源的分配与线程无关,线程只能共享它所属进程的资源。
4、标准LINUX的进程具有独立的虚拟地址空间,而一个进程里面的多个线程共享同一个虚拟内存空间,进程是系统所有资源分配时候的一个基本单位
嵌入式LINUX 2.6和2.4有什么区别?
这个问题涉及的面非常广泛,我们只能列出基本部分:
每个内核主要的变化在http://lwn.net/Articles/2.6-kernel-api/,详细的参考http://blog.mcuol.com/User/bailang/Article/11222_1.htm, 下面列举的是比较基础和必须的部分
1.使用新的入口
必须包含 module_init(your_init_func); module_exit(your_exit_func); 老版本:int init_module(void); void cleanup_module(voi); 2.4中两种都可以用,对如后面的入口函数不必要显示包含任何头文件。
2、模块参数
必须显式包含 module_param(name, type, perm); module_param_named(name, value, type, perm); 参数定义
module_param_string(name, string, len, perm); module_param_array(name, type, num, perm); 老版本:MODULE_PARM(variable,type); MODULE_PARM_DESC(variable,type);
3、模块别名
MODULE_ALIAS("alias-name"); 这是新增的,在老版本中需在/etc/modules.conf配置,现在在代码中就可以实现。
4、模块计数
int try_module_get(&module); module_put(); 老版本:MOD_INC_USE_COUNT 和 MOD_DEC_USE_COUNT
5、符号导出
只有显示的导出符号才能被其他模块使用,默认不导出所有的符号,不必使用EXPORT_NO _SYMBOLS 老板本:默认导出所有的符号,除非使用EXPORT_NO_SYMBOLS
6、设备号
kdev_t被废除不可用,新的dev_t拓展到了32位,12位主设备号,20位次设备号。
unsigned int iminor(struct inode *inode); unsigned int imajor(struct inode *inode); 老版本:8位主设备号,8位次设备号 int MAJOR(kdev_t dev); int MINOR(kdev_t dev);
7、内存分配头文件变更
所有的内存分配函数包含在头文件,而原来的不存在
老版本:内存分配函数包含在头文件
8、结构体的初试化
gcc开始采用ANSI C的struct结构体的初始化形式: static struct some_structure = { .field1 = value, .field2 = value, ..}; 老版本:非标准的初试化形式
static struct some_structure = { field1: value, field2: value, ..};
9、request_module() request_module("foo-device-%d", number); 老版本:
char module_name[32]; printf(module_name, "foo-device-%d", number); request_module(module_name);
10、dev_t引发的字符设备的变化
1、取主次设备号为
unsigned iminor(struct inode *inode); unsigned imajor(struct inode *inode);
2、老的register_chrdev()用法没变,保持向后兼容,但不能访问设备号大于256的设备。
3、新的接口为
a)注册字符设备范围
int register_chrdev_region(dev_t from, unsigned count, char *name); b)动态申请主设备号
int alloc_chrdev_region(dev_t *dev, unsigned baseminor, unsigned count, char *name); 看了这两个函数郁闷吧^_^!怎么和file_operations结构联系起来啊?别急! c)包含 ,利用struct cdev和file_operations连接 struct cdev *cdev_alloc(void); void cdev_init(struct cdev *cdev, struct file_operations *fops); int cdev_add(struct cdev *cdev, dev_t dev, unsigned count); (分别为,申请cdev结构,和fops连接,将设备加入到系统中!好复杂啊!) d)void cdev_del(struct cdev *cdev); 只有在cdev_add执行成功才可运行。 e)辅助函数
kobject_put(&cdev->kobj); struct kobject *cdev_get(struct cdev *cdev); void cdev_put(struct cdev *cdev); 这一部分变化和新增的/sys/dev有一定的关联。
11、新增对/proc的访问操作 以前的/proc中只能得到string, seq_file操作能得到如long等多种数据。 相关函数:
static struct seq_operations 必须实现这个类似file_operations得数据中得各个成 员函数。
seq_printf();
int seq_putc(struct seq_file *m, char c); int seq_puts(struct seq_file *m, const char *s); int seq_escape(struct seq_file *m, const char *s, const char *esc); int seq_path(struct seq_file *m, struct vfsmount *mnt, struct dentry *dentry, char *esc); seq_open(file, &ct_seq_ops); 等等
12、底层内存分配
1、头文件改为
2、分配标志GFP_BUFFER被取消,取而代之的是GFP_NOIO 和 GFP_NOFS
3、新增__GFP_REPEAT,__GFP_NOFAIL,__GFP_NORETRY分配标志
4、页面分配函数alloc_pages(),get_free_page()被包含在中
5、对NUMA系统新增了几个函数:
a) struct page *alloc_pages_node(int node_id, unsigned int gfp_mask, unsigned int order); b) void free_hot_page(struct page *page); c) void free_cold_page(struct page *page);
13、内核时间变化
1、现在的各个平台的HZ为
Alpha: 1024/1200; ARM: 100/128/200/1000; CRIS: 100; i386: 1000; IA-64: 1024; M68K: 100; M68K-nommu: 50-1000; MIPS: 100/128/1000; MIPS64: 100; PA-RISC: 100/1000; PowerPC32: 100; PowerPC64: 1000; S/390: 100; SPARC32: 100; SPARC64: 100; SuperH: 100/1000; UML: 100; v850: 24-100; x86-64: 1000.
2、由于HZ的变化,原来的jiffies计数器很快就溢出了,引入了新的计数器jiffies_64
3、#include u64 my_time = get_jiffies_64();
4、新的时间结构增加了纳秒成员变量
struct timespec current_kernel_time(void);
5、他的timer函数没变,新增
void add_timer_on(struct timer_list *timer, int cpu);
6、新增纳秒级延时函数 ndelay();
7、POSIX clocks 参考kernel/posix-timers.c
14、工作队列(workqueue)
1、任务队列(task queue )接口函数都被取消,新增了workqueue接口函数 struct workqueue_struct *create_workqueue(const char *name); DECLARE_WORK(name, void (*function)(void *), void *data); INIT_WORK(struct work_struct *work, void (*function)(void *), void *data); PREPARE_WORK(struct work_struct *work, void (*function)(void *), void *data);
2、申明struct work_struct结构
int queue_work(struct workqueue_struct *queue, struct work_struct *work); int queue_delayed_work(struct workqueue_struct *queue, struct work_struct *work, unsigned long delay); int cancel_delayed_work(struct work_struct *work); void flush_workqueue(struct workqueue_struct *queue); void destroy_workqueue(struct workqueue_struct *queue); int schedule_work(struct work_struct *work); int schedule_delayed_work(struct work_struct *work, unsigned long delay);
15、DMA的变化 未变化的有:
void *pci_alloc_consistent(struct pci_dev *dev, size_t size, dma_addr_t *dma_handle); void pci_free_consistent(struct pci_dev *dev, size_t size, void *cpu_addr, dma_addr_t dma_handle); 变化的有:
1、void *dma_alloc_coherent(struct device *dev, size_t size, dma_addr_t *dma_handle, int flag); void dma_free_coherent(struct device *dev, size_t size, void *cpu_addr, dma_addr_t dma_handle);
2、列举了映射方向:
enum dma_data_direction { DMA_BIDIRECTIONAL = 0, DMA_TO_DEVICE = 1, DMA_FROM_DEVICE = 2, DMA_NONE = 3, };
16、新增完成事件(completion events) init_completion(&my_comp); void wait_for_completion(struct completion *comp); void complete(struct completion *comp); void complete_all(struct completion *comp);
25、RCU(Read-copy-update) rcu_read_lock();
中断处理
1、中断处理有返回值了。 IRQ_RETVAL(handled);
2、cli(), sti(), save_flags(), 和 restore_flags()不再有效,应该使用local_save _flags() 或local_irq_disable()。
3、synchronize_irq()函数有改动
4、新增int can_request_irq(unsigned int irq, unsigned long flags);
5、request_irq() 和free_irq() 从 改到了
18、异步I/O(AIO) ize_t (*aio_read) (struct kiocb *iocb, char __user *buffer, size_t count, loff_t pos); ize_t (*aio_write) (struct kiocb *iocb, const char __user *buffer, size_t count, loff_t pos); int (*aio_fsync) (struct kiocb *, int datasync); 新增到了file_operation结构中。
is_sync_kiocb(struct kiocb *iocb);
int aio_complete(struct kiocb *iocb, long res, long res2);
19、block I/O 层
这一部分做的改动最大。不祥叙。
20.内核的一些功能函数的名称、参数、头文件、宏定义的变化
如:中断注册函数的格式及参数在2.4内核、2.6内核低版本和高版本之间都存在差别
在2.6.8中,中断注册函数的定义为:
int request_irq(unsigned int irq, irqreturn_t (*handler)(int, void *, struct pt_regs *),unsigned long irq_flags, const char * devname, void *dev_id) irq_flags的取值主要为下面的某一种或组合: SA_INTERRUPT、SA_SAMPLE_RANDOM、SA_SHIRQ 在2.6.26中,中断注册函数的定义为: int request_irq(unsigned int irq, irq_handler_t handler,unsigned long irqflags, const char *devname, void *dev_id) typedef irqreturn_t (*irq_handler_t)(int, void *); irq_flags的取值主要为下面的某一种或组合:(功能和2.6.8的对应) IRQF_DISABLED、IRQF_SAMPLE_RANDOM、IRQF_SHARED平台代码关于硬件操作方面封装的一些函数的变化
内 核中,硬件平台相关的代码在内核更新过程中变化比较频繁。和我们的设备驱动也是息息相关。所以在针对一个新内核编写设备驱动前,一定要熟悉你的平台代码的 结构。有时平台虽然提供了内核要求的接口函数,但使用起来功能却并不完善。下面还是先举个例子说明平台代码更新对设备驱动的影响。 如: 在linux-2.6.8内核中,调用set_irq_type(IRQ_EINT0, IRQT_FALLING);去设置S3C2410的IRQ_EINT0的中断触发信号类型,你会发现不会有什么效果。跟踪代码发现内核的 set_irq_type函数需要平台提供一个针对硬件平台的实现函数
static struct irqchip s3c_irqext_chip = { .mask = s3c_irqext_mask, .unmask = s3c_irqext_unmask, .ack = s3c_irqext_ack, .type = s3c_irqext_type }; s3c_irqext_type就是linux内核需要的实现函数,而s3c_irqext_type在2.6.8中的实现为:
static int s3c_irqext_type(unsigned int irq, unsigned int type) { irqdbf("s3c_irqext_type: called for irq %d, type %d\n", irq, type); return 0; } 原来并没有实现。而在较高版本的内核,如2.6.26内核中,这个函数是实现了的。