问题1
readl和writel的定义
之前由于自己定义了一个readl出现的错误
#define readl(addr) *(unsigned int*)(addr)
while(readl(xxxx));
也就是不停读取xxx地址的值。如果不是0.那么跳出循环,一般用于读取物理硬件寄存器
由于编译器认为读取的xxx的地址没有变化以及优化的问题。可能最终会优化成
ldr r3,[xxxx]
1:
tst r3,0
beq 1b
导致死循环并且不再读取xxx地址里面的值
所以必须要用一些编译语句让他不优化,或者变成
1:
ldr r3,[xxxx]
tst r3,0
beq 1b
比如
#define __arch_getl(a) (*(volatile unsigned int *)(a))
#define __arch_putl(v,a) (*(volatile unsigned int *)(a) = (v))
#define mb() asm volatile("dsb sy" : : : "memory")
#define dmb() __asm__ __volatile__ ("" : : : "memory")
#define __iormb() dmb()
#define __iowmb() dmb()
#define writel(v,c) ({ u32 __v = v; __iowmb(); __arch_putl(__v,c); __v; })
#define readl(c) ({ u32 __v = __arch_getl(c); __iormb(); __v; })
问题2
由于编译地址导致的访问问题
在内核开启mmu之前访问的一直是物理地址
如果在输出打印为puts("aaaaaaaaaaaaaaaaaa")
那么aaaaaaaaaaaaa可能存放在虚拟地址的0XC0100000
编译以后就会变成
ldr r0,=0XC0100000
bl puts
但是没有开启mmu,代码此时可能在物理地址0x20000000
puts里面去访问0xc01000000就会崩溃了
所以要使得这个aaaaaaaaaaa的地址是相对的。要在编译时加上-fpic指令。也就是代码地址无关。
编译后会变成
LDR R0, =(0xc0100000 - 0xc00accccd)
ADD R0, PC, R0
通过使用pc来定位。避免地址相关
这个-fpic指令可以在MakeFile中通过添加
ccflags-y := -fpic 或者找到对应的位置来添加
问题3
特别注意不要将所有的寄存器都当做标准寄存器使用,在start_kernel汇编的阶段,不一定是标准用法。
比如SP寄存器 不一定是可以用的堆栈寄存器。
我想在汇编阶段语句A和语句B之间执行一些打印。所以使用了下列方式
语句A
push {xxxxxxxxxxx}
打印
pop{xxxxxxxxx}
语句B
结果崩溃了。原因是开启mmu前后
ldr r13, =__mmap_switched @ address to jump to after
@ mmu has been enabled
badr lr, 1f @ return (PIC) address
使用了r13也就是sp寄存器保存__mmap_switched地址
并且修改了lr寄存器
一直到
__mmap_switched:
adr r3, __mmap_switched_data
ldmia r3!, {r4, r5, r6, r7}
cmp r4, r5 @ Copy data segment if needed
1: cmpne r5, r6
ldrne fp, [r4], #4
strne fp, [r5], #4
bne 1b
mov fp, #0 @ Clear BSS (and zero fp)
1: cmp r6, r7
strcc fp, [r6],#4
bcc 1b
ARM( ldmia r3, {r4, r5, r6, r7, sp})
最后才从r3中恢复了sp寄存器
要到这里以后才能正常使用sp 寄存器。(调试了5天)