资源描述
1.申请一个char指针和一个int指针他们所占的内存分别是多少,指向的数据所占内存分别是多少?
32位CPU 4字节
Char型1字节
Int型4字节
2. 物理地址,虚拟地址,逻辑地址和总线地址的区别
逻辑地址(Logical Address)是指由程序产生的与段相关的偏移地址部分。例如,你在进行C语言指针编程中,可以读取指针变量本身值(&操作),实际上这个值就是逻辑地址,它是相对于你当前进程数据段的地址,不和绝对物理地址相干。只有在Intel实模式下,逻辑地址才和物理地址相等(因为实模式没有分段或分页机制, Cpu不进行自动地址转换);逻辑也就是在Intel 保护模式下程序执行代码段限长内的偏移地址(假定代码段、数据段如果完全一样)。应用程序员仅需与逻辑地址打交道,而分段和分页机制对您来说是完全透明的,仅由系统编程人员涉及。应用程序员虽然自己可以直接操作内存,那也只能在操作系统给你分配的内存段操作。
线性地址(Linear Address)是逻辑地址到物理地址变换之间的中间层。程序代码会产生逻辑地址,或者说是段中的偏移地址,加上相应段的基地址就生成了一个线性地址。如果启用了分页机制,那么线性地址可以再经变换以产生一个物理地址。若没有启用分页机制,那么线性地址直接就是物理地址。Intel 80386的线性地址空间容量为4G(2的32次方即32根地址总线寻址)。
物理地址(Physical Address) 是指出现在CPU外部地址总线上的寻址物理内存的地址信号,是地址变换的最终结果地址。如果启用了分页机制,那么线性地址会使用页目录和页表中的项变换成物理地址。如果没有启用分页机制,那么线性地址就直接成为物理地址了。
在x86下,外设的i/o地址是独立的,即有专门的指令访问外设i/o,i/o地址就是你所说的“总线地址”。而“物理地址”就是ram地址。
在arm中,i/o和ram统一编址,但linux为了统一各个平台,仍然保留这个概念,其实就是物理地址。
3. 编写内核程序中申请内存和编写应用程序时申请内存有什么区别
应用程序使用C函数库中的内存分配函数malloc()申请内存
内核会为进程使用的代码和数据空间维护一个当前位置的值brk,这个值保存在每个进程的数据结构中。它指出了进程代码和数据(包括动态分配的数据空间)在进程地址空间中的末端位置。当malloc()函数为程序分配内存时,它会通过系统调用brk()把程序要求新增的空间长度通知内核,内核代码从而可以根据malloc()所提供的信息来更新brk的值,但此时并不为新申请的空间映射物理内存页面。只有当程序寻址到某个不存在对应物理页面的地址时,内核才会进行相关物理内存页面的映射操作。
当用户使用内存释放函数free()动态释放已申请的内存块时,c库中的内存管理函数就会把所释放的内存块标记为空闲,以备程序再次申请内存时使用。在这个过程中内核为该进程所分配的这个物理页面并不会被释放掉。只有当进程最终结束时内核才会全面收回已分配和映射到该进程地址空间范围内的所有物理内存页面。
4.触摸屏驱动中轮询模式和中断模式有什么区别
5.驱动编程中如何实现中断
以GPF引脚驱动为例,首先在模块初始化函数中设置外部中断,即把外部中断写入中断向量表,申请外部中断,模块打开函数中使能外部中断,模块退出函数释放外部中断。
6.如何调试编写的驱动程序来判断错误。
一般用printk函数打印一些内容
Kgdb结合gdb设置断点、单步执行、观察变量的值
7、驱动程序的编写流程
8、如何写linux驱动 写过哪些驱动
Gpf引脚驱动、pod驱动、AD驱动、
9、编程时用户空间和内核空间内存分配的区别
10、 linux中如何进行物理地址到虚拟地址的内存映射
本文分析了AT91SAM9261EK板子上9261芯片自带的LCD控制器的驱动程序中是如何实现从物理地址到内核虚拟地址的映射。
当系统执行/drivers/video/atmel_lcdfb.c中的atmel_lcdfb_init()时,调用
platform_driver_probe(&atmel_lcdfb_driver, atmel_lcdfb_probe)函数,首先以atmel_lcdfb_driver中()的name "atmel_lcdfb"为依据来搜索系统注册的device中有没有这个platform_device,如果有这个设备,则向系统注册该设备的驱动。
static struct platform_driver atmel_lcdfb_driver = {
.remove =
__exit_p(atmel_lcdfb_remove),
.driver = {
.name =
"atmel_lcdfb",
.owner = THIS_MODULE,
},
};
由于在/arch/arm/mach-at91/at91sam9261_devices.c中有下面的platform_device at91_lcdc_device,
static struct platform_device at91_lcdc_device = {
.name =
"atmel_lcdfb",
.id = 0,
.dev = {
.dma_mask = &lcdc_dmamask,
.coherent_dma_mask = 0xffffffff,
.platform_data = &lcdc_data,
},
.resource = lcdc_resources,
.num_resources =
ARRAY_SIZE(lcdc_resources),
};
它的name也为"atmel_lcdfb",并且在at91_add_device_lcdc()函数中已经向系统注册了该设备,所以当执行
atmel_lcdfb_probe()函数中的map = platform_get_resource(pdev, IORESOURCE_MEM, 1)时,即可得到下面定义的lcdc_resources参数,其中AT91SAM9261_LCDC_BASE即为 LCD User Interface 的起始地址0x600000,也即物理地址;AT91SAM9261_LCDC_BASE + SZ_4K
- 1为结束地址。
static struct resource lcdc_resources[] = {
[0] = {
.start =
AT91SAM9261_LCDC_BASE,
.end =
AT91SAM9261_LCDC_BASE + SZ_4K - 1,
.flags =
IORESOURCE_MEM,
},
[1] = {
.start = AT91SAM9261_ID_LCDC,
.end =
AT91SAM9261_ID_LCDC,
.flags =
IORESOURCE_IRQ,
},
#if defined(CONFIG_FB_INTSRAM)
[2] = {
.start =
AT91SAM9261_SRAM_BASE,
.end =
AT91SAM9261_SRAM_BASE + AT91SAM9261_SRAM_SIZE - 1,
.flags =
IORESOURCE_MEM,
},
#endif
};
然后通过ioremap()函数实现从物理地址到内核虚拟地址的映射,也即sinfo->mmio
= ioremap(info->fix.mmio_start, info->fix.mmio_len);其中的
info->fix.mmio_start = regs->start(即AT91SAM9261_LCDC_BASE);
info->fix.mmio_len = regs->end(即AT91SAM9261_LCDC_BASE + SZ_4K - 1)
- regs->start + 1;
11、用户态进程的虚拟地址如何转换成物理地址?
区分一个进程,我们都知道最简单就是进程的pid。我们就从(pid,virtualaddress)来看看如何将一个进程的虚拟地址转换为物理地址phyaddress。
首先根据pid我们可以得到这个进程的task_struct,进而通过task_struct得到mm,通过mm得到pgd。
好了,现在我们有pgd和virtualaddress.
通过pgd和virtualaddress我们可以得到页表pte.
有了pte和virtualaddress,我们就可以计算物理地址了
phyaddress=(pte_val(pte)&PAGE_MASK)|(virtualladdress&~PAGE_MASK)
物理地址既然出来了,访问这个地址的值就比较简单了,只需要将物理地址转换为内核线性地址就行。
*phyaddress=*((char *)phyaddress+PAGE_OFFSET)
12.、如何用C语言实现读写寄存器变量
#define rBANKCON0 (*(volatile unsigned long *)0x48000004)
rBankCON0 = 0x12;
13、希望做linux的上层应用 还是底层驱动?
14、liinux驱动编程时如何调试?
一般用printk函数打印一些内容
15、是否愿意做测试
16、linux系统编写驱动时,怎样用C语言去访问硬件,比如怎样读写寄存器
17、linux怎样调试程序
18、嵌入式软件开发流程
19、在编写驱动时,发现出现了错误,但不清楚是硬件还是驱动的问题,怎么去定
位 问题所在
20、是否愿意服从公司工作安排
展开阅读全文