ARM Linux的面试题

1. ARM

 MMU是什么? 存储器管理单元

 TTBR是什么?Translation table base register

名稱

說明

TranslationTable Base Register 0 (TTBR0)

用來記錄User-Mode應用Task的記憶體分頁架構所在的BaseAddress,通常大小為128bytes16kbytes(也就是說每個Task1st LevelTable可以有324kItems(也就是1st LevelTable Index的最大長度),可透過TTBCR.N值決定),當作業系統進行ContextSwitch,會把這個暫存器的值,指到新的Task的記憶體分頁架構的BaseAddress,並更新TTBCRCONTEXTIDR暫存器.如果TTBCR設定為0,則以ARMv6以前的架構來操作TTBR0.(也就是說只有一個TTBR,User-ModeKernel-Mode的記憶體分頁都透過它描述,相對的當Context-Switch發生時,就缺少分出TTBR0TTBR1的彈性).

TranslationTable Base Register 1 (TTBR1)

用來記錄作業系統特權等級與I/O空間的記憶體分頁架構所在的BaseAddress,屬於這類的記憶體規劃,並不會隨著應用TaskContext-Switch而改變.通常這Table大小都為16Kbytes.(就是說1stLevel Table可以有最多4kItems(=1st Level Table Index的最大長度)).

TranslationTable Base Control Register (TTBCR)

在沒有 TrustZone Security Extensions支援的環境下,對應的欄位如下所示

31 – 3

2 – 0

UNK/SBZP

N

 

其中N[2:0]用以表示TTBR0的寬度,也就是說TTBR0BaseAddressBits數為[31:14-N],如果N=0,表示TTBR0對應的Table大小為14bits=16kbytes,如果N=b111=7,表示TTBT0對應的Table大小為7bits=128bytes.

 

ARM 两级页表的映射?

ARM MMU只支持两级页表地址转换,也就是采用三级分页映射,能够满足32bitCPU的存储管理需求



ARM支持的页大小有几种 - 1M, 64K, 4K, 1K。在linux kernel中,ARM采用了4K大小的页,4K大小的页决定了虚拟地址的低12bit留作偏移地址。从上图可以看出,页全局目录索引有效位数是12bit,二级索引有效位数是8bit,页内偏移量为12bit。

根据ARM的硬件分页机制,我们得出第一级全局页目录有4096项,第二级为256项,这样第二级可以有很多位可以被硬件使用。

在arm linux实现上,针对ARM的硬件分页机制做了些微小的调整。第一级目录保留了2048项,每项占用8 bytes(换句话说,是两个硬件指针指向二级页表);第二级则把两个硬件PTE表连续放在一起,在这两个PTE表后面则保存相应的Linux状态信息,因此二级表项实际上有512项(每个表256项,两个则为512项)。这样每个逻辑PTE表刚好占用一个page。

ARM linux页表layout如下:


在arch/arm/include/asm/pgtable.h中,可以看到PTRS_PER_PTE和PTRS_PER_PTE的定义

[cpp] view plain copy
  1. #define PTRS_PER_PTE        512  
  2. #define PTRS_PER_PMD        1  
  3. #define PTRS_PER_PGD        2048  

由于PGD有2048项,每项占用8个字节,总计需要4*4K,也就是说ARM linux的PGD实际上占用了四个连续物理页框。

ARM Cache的flush & clean?

清除cache的意思是清除cache中存储的全部数据。对处理器而言,清除操作只要清零相应cache行的有效位即可。当存储器配置上有变化时,整体或部分cache可能需要进行清除操作。有时也用术语作废(invalidate)来代替术语“清除”。然而,对于采用写回策略的D-cache,就需要使用清理(clean)操作。
    清理cache的意思是把脏的(即被改写过的)cache行强制写到主存,并把cache行中的脏位清零。清理cache可以重建cache与主存之间的一致性,它只用在使用写回策略的D-cache上。
    改变系统的存储器配置可能要执行清除和清理cache的操作。访问权限、cache和缓冲策略的变化或者重新映射虚拟地址等操作都需要清理或清除cache。
    在分离cache中执行自修改代码之前,cache也需要执行清理和清除操作。自修改代码包括将代码简单地从一个地方拷贝到另一个地方。清理和清除操作是由两种可能的情况引起的:第一,自修改代码可能别承载在D-cache中,因此,不可能作为一条指令从主存中进行加载;第二,I-cache中现存的指令可能会屏蔽写到主存中的新指令。
    如果cache使用写回策略并且自修改代码被写入主存中,那么第一步就是将指令以数据块的形式写到主存中某处;稍后,程序跳转到主存中,以指令流的形式从主存中的该处开始执行。其中,当代码作为数据写入到主存中时,如果cache存储器中代表自修改代码被写入的主存位置的cache行有效,那么代码有可能会被写入到cache中(没有写入主存)。这些cache行会被拷贝到D-cache,而不是被拷贝到主存。如果发生了这种情况,那么当程序跳转到自修改代码所在的地方(主存某处)时,就会执行原来数据表示的代码,因为自修改代码此时实际上还在D-cache中。为了防止这种情况发生,可以进行D-cache的清理操作,把指令代码强制作为数据存到主存中,从而这些数据就可以作为指令流从主存中读出来。
    D-cache被清理后,新的指令就被写到主存中。但是,I-cache中可能会有效cache行存储新数据(代码)地址对应的指令。接下来,在新代码所在的地址读取指令时,仍然会得到I-cache中的老代码,而不是主存中的新代码。清除I-cache可以防止这种情况的发生。
    在linux的代码中涉及到自搬运代码的地方有:
1.    应用程序的装载:
Load_aout_binary
Load_aout_libary
Load_aout_interp
Load_flat_file

2.    Fiq代码的搬运:
3.    Signal.c中:
Setup_frame
Setup_rt_frame

ARM - V7 cache line的长度?


write-through & write back的区别?

write-back是cpu写操作,则把数据更新至cache,如果该数据发生了改变,置“dirty”标记,在cache line被置换或者cache flush的时候,数据写回 main memory.

2. Linux kernel

Kernel stack的大小? 8k in 2.4, shared by kernel and user, 4k after

stack的底部是什么?

in 8K stack of 2.4, task_struct is at the bottom of stack, which may cost about 1K, in 4K stack of 2.6, only thread_info is at the bottom of stack, the task_struct is put into a per-CPU data structre, thread_info is only about 50 bytes.

spin_lock & semaphore有什么区别?

spin_lock等同与循环访问,因此临界区的代码不能休眠,通常比较简洁。

semaphore的信号量会涉及到shedule(), 临界区代码可以进入休眠状态。

static的几种用法?

    1.static变量:
    1).局部
    a.静态局部变量在函数内定义,生存期为整个源程序,但作用域与自动变量相同,只能在定义该变量的函数内使用。退出该函数后, 尽管该变量还继续存在,但不能使用它。
    b.对基本类型的静态局部变量若在说明时未赋以初值,则系统自动赋予0值。而对自动变量不赋初值,则其值是不定的。
    2).全局
    全局变量本身就是静态存储方式, 静态全局变量当然也是静态存储方式。但是他们的作用域,非静态全局 变量的作用域是整个源程序(多个源文件可以共同使用); 而静态全局变量则限制了其作用域, 即只在定义该变量的源文件内有效, 在同一源程序的其它源文件中不能使用它。
    2.static函数(也叫内部函数)
    只能被本文件中的函数调用,而不能被同一程序其它文件中的函数调用。区别于一般的非静态函数(外部函数)

gcc 的编译优化选项?

O0 -->> O1 -->> O2 -->> O3

-O0表示没有优化,-O1为缺省值,-O3优化级别最高

几个section: bss, data, text...?

bss段:

BSS段(bsssegment)通常是指用来存放程序中未初始化的全局变量的一块内存区域。BSS是英文BlockStarted by Symbol的简称。BSS段属于静态内存分配。

data段:

数据段(datasegment)通常是指用来存放程序中已初始化的全局变量的一块内存区域。数据段属于静态内存分配。

text段:

代码段(codesegment/textsegment)通常是指用来存放程序执行代码的一块内存区域。这部分区域的大小在程序运行前就已经确定,并且内存区域通常属于只读,某些架构也允许代码段为可写,即允许修改程序。在代码段中,也有可能包含一些只读的常数变量,例如字符串常量等。

rodata段:

存放C中的字符串和#define定义的常量

heap堆:

堆是用于存放进程运行中被动态分配的内存段,它的大小并不固定,可动态扩张或缩减。当进程调用malloc等函数分配内存时,新分配的内存就被动态添加到堆上(堆被扩张);当利用free等函数释放内存时,被释放的内存从堆中被剔除(堆被缩减)

stack栈:

是用户存放程序临时创建的局部变量,也就是说我们函数括弧“{}”中定义的变量(但不包括static声明的变量,static意味着在数据段中存放变量)。除此以外,在函数被调用时,其参数也会被压入发起调用的进程栈中,并且待到调用结束后,函数的返回值也会被存放回栈中。由于栈的先进先出特点,所以栈特别方便用来保存/恢复调用现场。从这个意义上讲,我们可以把堆栈看成一个寄存、交换临时数据的内存区。

动态链接库 & 静态链接库的区别?

静态连接库就是把(lib)文件中用到的函数代码直接链接进目标程序,程序运行的时候不再需要其它的库文件;动态链接就是把调用的函数所在文件模块(DLL)和调用函数在文件中的位置等信息链接进目标程序,程序运行的时候再从DLL中寻找相应函数代码,因此需要相应DLL文件的支持。  

静态链接库与动态链接库都是共享代码的方式,如果采用静态链接库,则无论你愿不愿意,lib 中的指令都全部被直接包含在最终生成的 EXE 文件中了。但是若使用 DLL,该 DLL 不必被包含在最终 EXE 文件中,EXE 文件执行时可以“动态”地引用和卸载这个与 EXE 独立的 DLL 文件。静态链接库和动态链接库的另外一个区别在于静态链接库中不能再包含其他的动态链接库或者静态库,而在动态链接库中还可以再包含其他的动态或静态链接库。


动态链接库加载的两种方式?

我们调用动态链接库有两种方法:一种是编译的时候,指明所依赖的动态链接库,这样loader可以在程序启动的时候,来所有的动态链接映射到内存中;一种是在运行过程中,通过dlopen和dlfree的方式加载动态链接库,动态将动态链接库加载到内存中。

这两种方式,从编程角度来讲,第一种是最方便的,效率上影响也不大,在内存使用上有些差别。

第一种方式,一个库的代码,只要运行过一次,便会占用物理内存,之后即使再也不使用,也会占用物理内存,直到进程的终止。
第二中方式,库代码占用的内存,可以通过dlfree的方式,释放掉,返回给物理内存。

这个差别主要对于那些寿命很长,但又会偶尔调用各种库的进程有关。如果是这类进程,建议采用第二种方式调用动态链接库。

你可能感兴趣的:(memory,Linux,Kernel)