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

本文详细介绍了一种从ARM裸机环境逐步过渡到Linux环境的过程。通过修改启动代码,实现SDRAM初始化、MMU配置及内存映射,并最终运行用户程序。此外,还介绍了如何在MMU环境下操作GPIO,实现LED的点亮。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

代码的顺序分别为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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值