Chinaunix首页 | 论坛 | 博客
  • 博客访问: 111804
  • 博文数量: 70
  • 博客积分: 25
  • 博客等级: 民兵
  • 技术积分: 361
  • 用 户 组: 普通用户
  • 注册时间: 2011-10-09 12:40
文章分类

全部博文(70)

文章存档

2013年(64)

2012年(4)

2011年(2)

我的朋友

分类: 嵌入式

2013-09-09 09:20:22

s3c2440外接RAM所在的地址空间0x30000000-0x34000000. MMU启用后,只能通过虚拟地址访问内存。线性地址就是虚拟地址。

下面是在u-boot进行试验的过程及代码:

将虚拟地址空间0x30000000-0x34000000映射到物理地址空间0x30000000-0x34000000
将虚拟地址空间0x48000000-0x60000000映射到物理地址空间0x48000000-0x60000000
以上映射的建立,使相应的虚拟地址与物理地址相同。

将虚拟地址空间0xc0000000-0xc4000000映射到物理地址空间0x30000000-0x34000000
以上映射建立后,虚拟地址空间0xc0000000-0xc4000000与0x30000000-0x34000000对应同一块物理地址空间。

当个修改0x30000000-0x34000000中某个地址的内容时,0xc0000000-0xc4000000中相应地址的内容也被修改了.

下面修改0x30130000的内容,然后查看0xc0130000的内容。其内容会相应的改变。
test.c文件的内容

#define COARSE_FLAGS    (1 | (1 << 4) ) //bit(1,0) = 01 coarse page base,
#define SMALL_MEM_FLAGS        (2 | (1 << 2) | ( 1 << 3)) //bit(1,0) = 10 4KB page, bit(3,2) = 11 write back cacheable
#define SMALL_IO_FLAGS        (2 ) //bit(1,0) = 10 4KB page, bit(3,2) = 00 nocached nobuffered


(*printf)(char *, ...) = 0x33f95964;

/*
 *前面0地址开始的4KB + 0x30000000开始的64MB
 *
 *1个一级页项表对应256个二级页表项
 *
 *1个二级页表项对应1个页帧
 *
 *1个页帧4KB
 *
 */


#define TTB 0x32000000; //ttb基址,也是一级页目录表基址
#define TTB_L2 (0x32000000 + 0x4000) //二级页表基址, 给一级页表留足16KB

unsigned long *ttb = (void *)TTB;
unsigned long *ttb_l2 = (void *)TTB_L2;

void memset(char *dst, char ch, int size);
void _start(void)
{
    unsigned long c1_flags;
    unsigned long virt, phys, temp, addr;
    int *p;

    memset(ttb, 0x00, 4096 * 4);

    c1_flags = 1 | (1 << 1) | (0xf << 3) | (0x3 << 30); //bit0 = 1 MMU enable,bit1 = 1 fault check, bit6..3 = 0xf write, bit31,30 = 0x3 async clock mode

/*第一个4KB, 第一页*/
    ttb[0] = ((unsigned long)ttb_l2) | COARSE_FLAGS;
    ttb_l2[0] = 0 | SMALL_MEM_FLAGS;
    ttb_l2 = TTB_L2 + 256 * 4;
/*线性地址空间[0x30000000, 0x34000000] 映射到物理地址空间[0x30000000, 0x34000000]*/
    for (addr = 0x30000000; addr < 0x34000000; ttb_l2 += 256) {
        ttb[addr >> 20]    = ((unsigned long )ttb_l2 & 0xfffffc00) | COARSE_FLAGS;

        temp = addr + 0x100000; //限定处理1MB空间对应的页表

        for (; addr < temp; addr += 0x1000) {
            ttb_l2[(addr & 0xff000) >> 12] = (addr & 0xfffff000) | SMALL_MEM_FLAGS;
        }    
    }
    
/*线性地址空间[0x48000000, 0x60000000] 映射到物理地址空间[0x48000000, 0x60000000]*/
    for (addr = 0x48000000; addr < 0x60000000; ttb_l2 += 256) {
        ttb[addr >> 20]    = ((unsigned long)ttb_l2 & 0xfffffc00) | COARSE_FLAGS;

        temp = addr + 0x100000; //限定处理1MB空间对应的页表

        for (; addr < temp; addr += 0x1000) {
            ttb_l2[(addr & 0xff000) >> 12] = (addr & 0xfffff000) | SMALL_IO_FLAGS;
        }
    }

/*线性地址空间[0xc0000000, 0xc4000000] 映射到物理地址空间[0x30000000, 0x34000000]*/
    for (virt = 0xc0000000; virt < 0xc4000000; ttb_l2 += 256) {
        ttb[virt >> 20]    = ((unsigned long )ttb_l2 & 0xfffffc00) | COARSE_FLAGS;

        temp = virt + 0x100000; //每一个一级页表项限定处理1MB空间对应的页表

        for (; virt < temp; virt += 0x1000) {
            phys = virt - 0xc0000000 + 0x30000000; //虚拟地址与物理地址之间的关系

            ttb_l2[(virt & 0xff000) >> 12] = (phys & 0xfffff000) | SMALL_MEM_FLAGS;
        }    
    }
//------------------------------------------


    __asm__ __volatile__ (    
        "mov r0, #0\n"            
        "mcr p15, 0, r0, c7, c7, 0\n" //清除I-cache和D-cache的内容:
        "mcr p15, 0, r0, c8, c7, 0\n" //清除I & D TLB 的内容

        "mvn r0, #0\n"
        "mcr p15, 0, r0, c3, c0, 0\n" //clear Domain access control
        //--------------------------------
        "mcr p15, 0, %1, c2, c0, 0\n" //ttb写入c2
        "mcr p15, 0, %0, c1, c0, 0\n" //c1_flags写入c1
        :
        : "r" (c1_flags), "r" (ttb)
        : "r0"
    );
/*先看初始值*/
    virt = 0x30130000;
    printf("0x30130000 = %x\n", *(int *)virt);
    virt = 0xc0130000;
    printf("0xc0130000 = %x\n", *(int *)virt);

/*修改0x30130000地址处的值, 再看0xc0130000处的值*/
    virt = 0x30130000;
    *(int *)virt = 0x2222;
    virt = 0xc0130000;
    printf("0xc0130000 = %x\n", *(int *)virt);

/*修改0x30130000地址处的值, 再看0xc0130000处的值*/
    virt = 0x30130000;
    *(int *)virt = 0x3333;
    virt = 0xc0130000;
    printf("0xc0130000 = %x\n", *(int *)virt);
}

void memset(char *dst, char ch, int size)
{
    int i;
    for (i = 0; i < size; i ++) {
        dst[i] = ch;
    }
}


Makefile内容:

PREFIX    = ~/tftpboot
EXEC_PREFIX    = /usr/local/arm/3.4.1/bin/arm-linux-
TARGET     ?= test

REMOVE    = rm -f

CC    = $(EXEC_PREFIX)gcc
LD    = $(EXEC_PREFIX)ld
OBJCOPY    = $(EXEC_PREFIX)objcopy

C_FLAGS    = -march=armv4 -c -o
LD_FLAGS    = -o

$(TARGET):$(TARGET:=.o)
    $(LD) -T $(@:=.lds) $(LD_FLAGS) $@ $^
    $(OBJCOPY) -I elf32-littlearm -O binary $@ $(PREFIX)/$(@:=.bin)

%.o:%.c
    $(CC) $(C_FLAGS) $@ $<

%.o:%.S
    $(CC) $(C_FLAGS) $@ $<


.PHONY:clean
clean:
    $(REMOVE) $(TARGET) $(TARGET:=.bin) $(TARGET:=.o) ~*


1.执行make之后生面test.bin文件
2.在u-boot的命令行界面加载test.bin文件
    tftp 30000000 test.bin
3.在u-boot的命令行界面执行
    go 30000000
4.显示结果:
## Starting application at 0x30000000 ...
    0x30130000 = 3333
       0xc0130000 = 3333
       0xc0130000 = 2222
       0xc0130000 = 3333
## Aplication terminated, rc = 0x0



阅读(964) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~