您的位置:首页 > 其它

[Funkunux] 自己写MMU实验 基于S3C2440

2016-07-20 11:24 239 查看
代码的顺序分别为head.S, led.c, Makefile
我把0x56000000映射到0xb0000000,把sdram的地址映射到0xa0000000,这里的做法也和韦老师的相反,主要内容是head.S

.text
.global _start
_start:
bl Disable_Watch_Dog
bl MemSetup
bl MMUSetup
bl Copy_SteppingStone_to_Sdram
ldr pc,=On_Sdram

Disable_Watch_Dog:              ;关看门狗
mov r1,#0x53000000
mov r2,#0
str r2,[r1]
mov pc,lr

MemSetup:                       ;初始化SDRAM
mov r1,#0x48000000
adrl r2,SetMem_avl
ldr r3,=0x48000034
Loop1:
ldr r4,[r2],#4
str r4,[r1],#4
cmp r1,r3
bne Loop1
mov pc,lr

Copy_SteppingStone_to_Sdram:    ;将程序复制到虚拟地址0xa0004000处运行
mov r1,#0
ldr r2,=0xa0004000
mov r3,#4096
Loop2:
ldr r4,[r1],#4
str r4,[r2],#4
cmp r3,r1
bne Loop2
mov pc,lr
MMUSetup:                       ;初始化MMU
;建立4G内存空间页表
mov r4,#0x30000000          ;页表基址
ldr r3,=0x00000c12          ;domain 0,uncached,unbuffered
mcr p15, 0, r4, c2, c0, 0   ;将页表基址存入C2中
ldr r5,=0x1000              ;循环4K次(4K*1MB=4GB)
l1:
str r3,[r4],#4              ;建立页表
add r3,r3,#(1<<20)          ;更新描述符
subs r5,r5,#1
bne l1

;映射0x56000000到0xb0000000
mov r4,#0x30000000          ;页表基址
ldr r3,=0x00000c12          ;domain 0,uncached,unbuffered
ldr r1,=0xfff00000
mov r2,#0xb0000000          ;VA
mov r0,#0x56000000          ;PA
and r2,r2,r1
orr r3,r3,r0                ;段描述符 4Byte
add r4,r4,r2,lsr #(18)      ;描述符地址=基址+虚拟段地址>>(20-2)位   ([1:0]位为00,4字节对齐)
str r3,[r4]
;映射0x30000000到0xa0000000
mov r4,#0x30000000
ldr r3,=0x00000c1e          ;domain 0,cached,buffered
ldr r1,=0xfff00000
mov r2,#0xa0000000          ;VA
mov r0,#0x30000000          ;PA
and r2,r2,r1
orr r3,r3,r0                ;段描述符 4Byte
add r4,r4,r2,lsr #(18)      ;描述符地址=基址+虚拟段地址>>(20-2)位   ([1:0]位为00,4字节对齐)
mov r5,#64                  ;SDRAM总共有64MB 循环64次
l2:
str r3,[r4],#4
add r3,r3,#(1<<20)
subs r5,r5,#1
bne l2

mov r0,#0
mcr p15,0,r0,c7,c7,0        ;使无效ICache和DCache
mcr p15,0,r0,c7,c10,4       ;清空缓冲区
mcr p15,0,r0,c7,c5,4        ;清空预取缓冲区
mcr p15,0,r0,c7,c5,6        ;清空整个跳转目标cache
mcr p15,0,r0,c8,c7,0        ;使无效TLB
mvn r0,#0
mcr p15,0,r0,c3,c0,0        ;域访问控制寄存器设为0xFFFFFFFF,不进行权限检查
mrc p15,0,r0,c1,c0,0        ;读取C1内容到R0
bic r0,r0,#0x3000
bic r0,r0,#0x380
bic r0,r0,#0x7
orr r0,r0,#0x1000
orr r0,r0,#0x7              ;开启对齐检查,使能ICache,使能DCache,打开MMU
mcr p15,0,r0,c1,c0,0        ;将R0中内容写回C1中
mov pc,lr
On_Sdram:
mov sp,#0xa4000000          ;设置栈顶在SDRAM最上方
bl main
Halt_loop:
b Halt_loop

.align 4
SetMem_avl:
@ 存储控制器13个寄存器的设置值
.long   0x02011110      @ BWSCON
.long   0x00000700      @ BANKCON0
.long   0x00000700      @ BANKCON1
.long   0x00000700      @ BANKCON2
.long   0x00000700      @ BANKCON3
.long   0x00000700      @ BANKCON4
.long   0x00000700      @ BANKCON5
.long   0x00018009      @ BANKCON6
.long   0x00018009      @ BANKCON7
.long   0x00aC07A3      @ REFRESH
.long   0x000000B1      @ BANKSIZE
.long   0x00000030      @ MRSRB6
.long   0x00000030      @ MRSRB7/*
* leds.c: 循环点亮4个LED
* 属于第二部分程序,此时MMU已开启,使用虚拟地址
*/

#define GPFCON      (*(volatile unsigned long *)0xb0000050)     // 物理地址0x56000050
#define GPFDAT      (*(volatile unsigned long *)0xb0000054)     // 物理地址0x56000054

#define        GPF4_out        (1<<(4*2))
#define        GPF5_out        (1<<(5*2))
#define        GPF6_out        (1<<(6*2))

/*
* wait函数加上“static inline”是有原因的,
* 这样可以使得编译leds.c时,wait嵌入main中,编译结果中只有main一个函数。
* 于是在连接时,main函数的地址就是由连接文件指定的运行时装载地址。
* 而连接文件mmu.lds中,指定了leds.o的运行时装载地址为0xB4004000,
* 这样,head.S中的“ldr pc, =0xB4004000”就是跳去执行main函数。
*/
static inline void wait(unsigned long dly)
{
for(; dly > 0; dly--);
}

int main(void)
{
unsigned long i = 0;

GPFCON = GPF4_out|GPF5_out|GPF6_out;                // 将LED1,2,4对应的GPF4/5/6三个引脚设为输出

while(1){
wait(30000);
GPFDAT = (~(i<<4));                 // 根据i的值,点亮LED1,2,4
if(++i == 8)
i = 0;
}

return 0;
}mmu.bin : head.S  led.c
arm-linux-gcc  -c -o head.o head.S
arm-linux-gcc -c -o led.o led.c
arm-linux-ld -Ttext 0xa0004000 head.o led.o -o mmu_elf
arm-linux-objcopy -O binary -S mmu_elf mmu.bin
arm-linux-objdump -D -m arm  mmu_elf > mmu.dis
clean:
rm -f   mmu.dis mmu.bin mmu_elf *.o
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  S3C2440 MMU ARM