S3C2440裸奔篇之MMU

;================================================
; head.S
; 功能: 关闭看门狗、设置SDRAM,创建页表,启动MMU、进入main函数
;================================================

 IMPORT disable_watch_dog  ; 声明关闭看门狗C函数
 IMPORT memsetup   ; 声明存储控制器设置C函数
 ;IMPORT copy_2th_to_sdram  ; 声明复制代码C函数
 IMPORT create_page_table  ; 声明设置页表C函数
 IMPORT mmu_init    ; 声明mmu初始化启动C函数
 IMPORT main    ; 声明C函数
 
 CODE32
 AREA    Init, CODE, READONLY
ENTRY

 ldr sp, =4096   ; 设置栈指针,以下都是C函数,且注意不可以大于4K
 bl disable_watch_dog  ; 关闭看门狗,否则CPU会不断重启
 bl memsetup   ; 设置存储控制器以便使用SDRAM(存放页表)
 ;bl copy_2th_to_sdram  ; 将第2部分led.c代码复制到SDRAM里
 bl create_page_table  ; 创建页表 
 bl mmu_init    ; 启动mmu
 bl main    ; 调用main函数
halt_loop
 b halt_loop

 END
 
 
 /******************************************************************************
** init.c: 进行一些初始化,在steppingstone中执行,
** 此时MMU未开启,使用物理地址,属于第1部分代码
******************************************************************************/

#define WTCON  (*(volatile unsigned long int *)0x53000000)  // WATCHDOG寄存器
#define MEM_CTL_BASE 0x48000000       //  存储控制器的寄存器起始地址

/*
 * 关闭看门狗,否则CPU会不断重启
 */
void disable_watch_dog(void)
{
 WTCON = 0;  // 关闭看门狗,写0即可
}

/*
 * 设置存储器控制器以便使用SDRAM存放页表
 */
void memsetup(void)
{
 /* SDRAM的13个寄存器的值 */
 unsigned long const mem_cfg_val[] = {  0x22011110,     // BWSCON
                                                0x00000700,     // BANKCON0
                                                 0x00000700,     // BANKCON1
                                                 0x00000700,     // BANKCON2
                                                 0x00000700,     // BANKCON3 
                                                 0x00000700,     // BANKCON4
                                                 0x00000700,     // BANKCON5
                                                 0x00018005,     // BANKCON6
                                                 0x00018005,     // BANKCON7
                                                 0x008C07A3,     // REFRESH
                                                 0x000000B1,     // BANKSIZE
                                                 0x00000030,     // MRSRB6
                                                 0x00000030,     // MRSRB7
         };
 int i = 0;
 volatile unsigned long *p = (volatile unsigned long *)MEM_CTL_BASE;
 for(; i<13; i++)
 {
  p[i] = mem_cfg_val[i];  // 给13个寄存器赋值
 }
}

/*
 * 创建页表
 */
void create_page_table(void)
{

/*
 * 用于段描述符的一些宏
 */
#define MMU_FULL_ACCESS  (3<<10)  // 访问权限为“读/写”
#define MMU_DOMAIN   (0<<5)   // 属于第0个域
#define MMU_SPECIAL   (1<<4)  // 必须是1
#define MMU_CACHEABLE   (1<<3)  // cache使能
#define MMU_BUFFERABLE   (1<<2)  // buffer使能
#define MMU_SECTION   (2)   // 表明这是段描述符
#define MMU_SECDESC   (MMU_FULL_ACCESS | MMU_DOMAIN | MMU_SPECIAL | MMU_SECTION)
#define MMU_SECDESC_WB  (MMU_FULL_ACCESS | MMU_DOMAIN | MMU_SPECIAL | MMU_CACHEABLE | MMU_BUFFERABLE | MMU_SECTION)

 unsigned long vir_add, phy_add;
 unsigned long *mmu_table_base = (unsigned long *)0x30000000;  // 此页表基地址与CP15的C2中存储的基地址是同一个地址
 
 /*
  * 将steppingstone在内的起始0~1M的虚拟地址映射到同样的物理地址
  */
  vir_add = 0;
  phy_add = 0;
  *(mmu_table_base + (vir_add >> 20)) = ((phy_add & 0xFFF00000) | MMU_SECDESC_WB); // 描述符的寻址及其属性定义(《ARM体系机构及编程》181页)
 
  /*
  * 0x56000000是GPIO寄存器的起始地址
  * GPBCON和GPBDAT这2个寄存器的物理地址是0x56000010和0x56000014
  * 为了可以在led.c的代码中用虚拟地址0xA0000010和0xA0000014操作GPBCON和GPBDAT
  * 将0xA0000000开始的1M虚拟地址映射到0x56000000开始的1M物理地址上
  */
 vir_add = 0xA0000000;
 phy_add = 0x56000000;
 *(mmu_table_base + (vir_add >> 20)) = ((phy_add & 0xFFF00000) | MMU_SECDESC);
 
 /*
  * SDRAM的物理地址是0x30000000~0x33FFFFFF,
  * 将SDRAM映射到同样的虚拟地址上
  * 共64M,涉及到64个段描述符
  */
  vir_add = 0x30000000;
  phy_add = 0x30000000;
  while(vir_add < 0x34000000)
  {
    *(mmu_table_base + (vir_add >> 20)) = ((phy_add & 0xFFF00000) | MMU_SECDESC_WB);
    vir_add += 0x100000;
    phy_add += 0x100000;  // 1M对齐
  }
}

/*
 * 启动mmu
 */
void mmu_init(void)
{
 // 内嵌汇编,操作CP15协处理器
 __asm{ 
   //MMU_SetTTBase,设置一级页表基地址(即存放页表的起始存储地址)
      mov r0,#0x30000000; // r0=TTBase 即页表的基地址
      mcr p15,0,r0,c2,c0,0; // C2中存放地址转换表基地址
     
      //映射之后,地址需经过MMU,它能控制你的访问权限。
      //域访问控制寄存器设为0xffffffff,就是让你有权限访问映射的空间
      mvn r0, #0;   // 数据取反传送指令
        mcr p15,0,r0,c3,c0,0; // 访问类型为管理者权限
  
   //MMU_EnableMMU,使能MMU
   mrc p15,0,r0,c1,c0,0; // 读出协处理器C1
   orr r0,r0,#01;   // 或操作,使最低位为1
   mcr p15,0,r0,c1,c0,0; // 给C1赋值 
  }
}

 

/******************************************************************************
** led.c: 点亮4个LED, 属于第2部分代码
** 此时MMU已开启,使用虚拟地址定位寄存器,但代码本身仍在SRAM中运行
*****************************************************************************/

#define GPBCON      (*(volatile unsigned long *)0xA0000010)     // 物理地址0x56000010
#define GPBDAT      (*(volatile unsigned long *)0xA0000014)     // 物理地址0x56000014

#define GPB5_out  (1<<(5*2))
#define GPB6_out  (1<<(6*2))
#define GPB7_out  (1<<(7*2))
#define GPB8_out  (1<<(8*2))


 void wait(unsigned long dly)
{
    for(; dly > 0; dly--);
}


int main(void)
{
 GPBCON = GPB5_out|GPB6_out|GPB7_out|GPB8_out;  // 将LED1-4对应的GPB5/6/7/8四个引脚设为输出

 while(1)
 {
  GPBDAT = 0x00000000;  // 亮
  wait(30000);
  GPBDAT = 0xFFFFFFFF;  // 灭
  wait(30000);
 }
 return 0;
}

---------------华丽分割线------------------------

在设置编译器的RO时设置为0x00000000,因为我的代码比较小,所以没有将代码复制到SDRAM里面,只是用SDRAM来储存页表,因此仍需要对SDRAM进行初始化。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值