韦东山Linux嵌入式课程社区
直播中

贺服窍

7年用户 976经验值
私信 关注

自己写的MMU实验还有哪里有问题吗?

代码的顺序分别为head.S, led.c, Makefile
其中,除了led.c是借鉴韦老师的点灯程序,其他都是自己写的,我把0x56000000映射到0xb0000000,把sdram的地址映射到0xa0000000,这里的做法也和韦老师的相反,主要内容是head.S
以下是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
  •    



复制代码

回帖(4)

徐静怡

2019-8-2 09:33:34
接下来是led.c代码:

  • /*
  • * 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;
  • }

复制代码
举报

张国厚

2019-8-2 09:47:41
最后是Makefile:

  • 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

复制代码
举报

陈铮

2019-8-2 10:00:43
哦 对了 我发现汇编代码的注释不能用分号";" 而应该用"@" 否则编译时会报错
举报

张依然

2019-8-2 10:19:50
阔以阔以/111
举报

更多回帖

发帖
×
20
完善资料,
赚取积分