在前面实验的基础上. 对MMU相关寄存器进行配置. 主要涉及到的是协处理器里的几个寄存器.
p15 c1: 这个寄存器中有几个比特位控制D/I cache 和 write buffer 主要是C/W/I比特位。
使能MMU的比特为M,地址对齐检查A等...
p15 c2: 保存顶级页表的物理基址, 相当于x86里的cr0寄存器的作用
p15 c3: 硬件实现的16个域的访问权限控制,这里简单的设置为全1,即不进行检查
p15 c7: 这个寄存器比较复杂,命令比较多,实验中所用到的命令是invalidate I/D cache. clean write buffer
p15 c8: invalidate TLB for D/I cache.、
为方便起见,只用一级页表,即段类型,一个页表项控制1MB的物理地址映射。
映射方案: 将steppingstone进行恒等映射,即将虚拟地址的第一个MB映射到物理地址的第一个MB,这也是为了方便。
GPIO地址0x56000000开始的1MB对应虚拟地址0xf6000000开始的1MB。
SDRAM地址0x3000000的SDRAM结束地址映射到虚拟地址的0xe0000000开始处。
其余的不作映射处理。
前面实验中的start.S只需要稍微修改一下, lowlevel_init.S不变, main.c文件也不变, 添加init.c文件初始化mmu,建立页表。将mian.c文件对应的代码拷贝到SDRAM偏移0x4000处(因为SDRAM偏移0 - 0x3ff放置页表),还有一个链接脚本,控制目标文件在二进制可执行文件中的位置。
start.S文件:
#define SDRAM_BASE 0x30000000
#define WATCHDOG 0x53000000
#define GPBCON 0x56000010
#define LED4_SET_OUTPUT ((1<<10) | (1<<12) | (1<<14) | (1<<16))
.text
.global _start
_start:
bl disable_watchdog
bl sdram_init
ldr sp, =4096
bl copy_main_to_sdram
bl paging_init
bl mmu_init
ldr sp, =0xe4000000
ldr pc, =0xe0004000
halt:
b halt
disable_watchdog:
ldr r0, =WATCHDOG
mov r1, #0
str r1, [r0]
mov pc, lr
init.c 文件
#define SDRAM_BASE 0x30000000
#define VIRTUAL_SDRAM_BASE 0xe0000000
#define SDRAM_LENGTH 0x4000000
#define PG_NO_CHECK (3<<10)
#define PG_DOMAIN (0<<5)
#define PG_RESERVED (1<<4)
#define PG_CACHED (1<<3)
#define PG_BUFFERED (1<<2)
#define PG_SECTION_TYPE (2<<0)
#define PG_SECTION_DCB (PG_NO_CHECK | PG_DOMAIN | PG_RESERVED \
| PG_SECTION_TYPE)
#define PG_SECTION_ECB (PG_SECTION_DCB | PG_CACHED | PG_BUFFERED)
#define SECTION_SIZE (0x100000UL)
#define SECTION_MASK (~(SECTION_SIZE - 1))
void copy_main_to_sdram(void)
{
/*
* when link the objects, i place the main.o at fixed pos, it's offset in the binay file is 2048
* see ld script in detail
*/
unsigned long *src = (unsigned long *)2048;
unsigned long *dst = (unsigned long *)(SDRAM_BASE + 0x4000);
while(src < (unsigned long *)4096) {
*dst = *src;
src++;
dst++;
}
}
void paging_init(void)
{
unsigned long vaddr, paddr;
unsigned long *sdram_base = (unsigned long *)SDRAM_BASE;
vaddr = 0;
paddr = 0;
*(sdram_base + (vaddr >> 20)) = (paddr & SECTION_MASK) \
| PG_SECTION_ECB;
/* GPIO MAPPING, should not be cacheable and bufferable */
vaddr = 0xf6000000;
paddr = 0x56000000;
*(sdram_base + (vaddr >> 20)) = (paddr & SECTION_MASK) \
| PG_SECTION_DCB;
vaddr = VIRTUAL_SDRAM_BASE;
paddr = SDRAM_BASE;
while(paddr < SDRAM_BASE + SDRAM_LENGTH) {
*(sdram_base + (vaddr >> 20)) = (paddr & SECTION_MASK) \
| PG_SECTION_DCB;
vaddr += SECTION_SIZE;
paddr += SECTION_SIZE;
}
}
void mmu_init(void)
{
unsigned long ttb = SDRAM_BASE;
__asm__ (
"mov r0, #0\n\t"
"mcr p15, 0, r0, c7, c7, 0\n\t" /* invalidate Dcache and Icache */
"mcr p15, 0, r0, c7, c10, 4\n\t" /* clean write buffer */
"mcr p15, 0, r0, c8, c7, 0\n\t" /* invalidate TLB for Dcache and Icache*/
"mov r0, %0\n\t" /* r4 = page table base addr*/
"mcr p15, 0, r0, c2, c0, 0\n\t"
"mvn r0, #0\n\t"
"mcr p15, 0, r0, c3, c0, 0\n\t" /* do not check the domain priv */
"mrc p15, 0, r0, c1, c0, 0\n\t" /* read c1 to r0 */
"bic r0, r0, #0x3000\n\t" /* diable Icache, low intrrupt vector */
"bic r0, r0, #0x300\n\t" /* clear R, S bit */
"bic r0, r0, #0x87\n\t" /* clear B\C\A\M bit */
"orr r0, r0, #0x2\n\t" /* set A bit */
"orr r0, r0, #0x4\n\t" /* set C bit */
"orr r0, r0, #0x1000\n\t" /* set I bit */
"orr r0, r0, #0x1\n\t" /* set M bit,namely enable MMU */
"mcr p15, 0, r0, c1, c0, 0\n\t"
::"r"(ttb));
}
Makefile 文件:
CROSS_COMPILE := arm-linux-
CC := $(CROSS_COMPILE)gcc
CPP := $(CROSS_COMPILE)gcc -E
AS := $(CROSS_COMPILE)as
LD := $(CROSS_COMPILE)ld
OBJCOPY := $(CROSS_COMPILE)objcopy
OBJ = start.o lowlevel_init.o init.o main.o
all:u-boot.bin
u-boot.bin: test_elf
$(OBJCOPY) -O binary -S $< $@
test_elf: $(OBJ)
$(LD) -Tld.lds -o $@ $^
.S.s:
$(CPP) -o $@ $<
.s.o:
$(AS) -o $@ $<
.c.o:
$(CC) -c -o $@ $<
.PHONY clean:
clean:
rm -f *.s *.o *.bin test_elf
ld.lds 链接脚本文件
SECTIONS {
start 0x00000000 : { start.o lowlevel_init.o init.o }
main 0xe0004000 : AT(2048) { main.o }
}
阅读(1711) | 评论(0) | 转发(0) |