[Funkunux] 自己写MMU实验 基于S3C2440
2016-07-20 11:24
239 查看
代码的顺序分别为head.S, led.c, Makefile
我把0x56000000映射到0xb0000000,把sdram的地址映射到0xa0000000,这里的做法也和韦老师的相反,主要内容是head.S
我把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
相关文章推荐
- #新闻拍一拍# IBM 招聘广告要求应聘者具备至少 12 年 K8S 使用经验
- vivi下重新调整分区
- ARM Linux系统启动
- Linux及ARM Linux程序开发笔记(零基础入门篇)
- 基于S3C2440的Linux-3.6.6移植
- 零基础入门篇之Linux及Arm-Linux程序开发笔记
- 我的 ARM+Linux 学习路线
- 64位Ubuntu 14.04上使用musleabi最小化交叉编译Android版PHP7
- 关于ARM启动的一篇文章
- ARM 的堆栈初始化详解
- ARM条件码与CPSR标志位的关系
- 加载/存储指令
- 关于ARM 汇编的一些疑问
- ARM汇编伪指令介绍
- s3c2440通过GPIO口控制三块74HC595
- linux的防火墙及arm与虚拟机共享
- 编译单个驱动的Makefile文件。
- 移植linux-2.6.30.4到S3C2440
- ARM Linux系统调用的原理
- Android LKM Rootkit,查找sys_call_table