1、概述
之前我们通过直接使用GPIO引脚来控制LED,也就是说中间没有MMU的参与,接下来我们通过使用虚拟地址来点亮led的功能,学习MMU的使用。
2、以段的方式(其他两种是粗页 细页)进行映射
解析:先通过虚拟地址的高12位取出来作为一个表(translation table)的偏移也叫一级页表的偏移,找到页表中的某一个表项,表项的高12位就指向段的物理基地址,拿出来该12位值(段基地址),和虚拟地址中的offset拼起来,合并成一个32位的地址,就组成了对应的物理地址。
在整个过程中MMU的功能:
①首先会去查一级页表,MMU是如何找到这种一级页表的呢?mmu会从cp15-c2寄存器中去找该表。也就是程序员在建立一级页表的时候需要把TTB写入到cp15-c2寄存器中。
3、写代码通过虚拟地址访问led
示意图:
4、代码
main.c
#define GPBCON (volatile unsigned long*)0xA0000010 #define GPBDAT (volatile unsigned long*)0xA0000014 /* * 用于段描述符的一些宏定义 */ #define MMU_FULL_ACCESS (3 << 10) /* 访问权限 */ #define MMU_DOMAIN (0 << 5) /* 属于哪个域 */ #define MMU_SPECIAL (1 << 4) /* 必须是1 */ #define MMU_CACHEABLE (1 << 3) /* cacheable */ #define MMU_BUFFERABLE (1 << 2) /* bufferable */ #define MMU_SECTION (2 << 0) /* 段描述符 */ #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) //1.建立页表 void create_page_table(void) { unsigned long *ttb = (unsigned long *)0x30000000; unsigned long vaddr, paddr; 映射LED地址 vaddr = 0xA0000000; paddr = 0x56000000; LED的物理基地址 //*(ttb + (vaddr >> 20))指向页表中的项 *(ttb + (vaddr >> 20)) = (paddr & 0xFFF00000) | MMU_SECDESC; 内存映射地址 vaddr = 0x30000000; paddr = 0x30000000; while (vaddr < 0x34000000) { 由于映射是以0x100000也就是1MB为单位的 *(ttb + (vaddr >> 20)) = (paddr & 0xFFF00000) | MMU_SECDESC_WB; vaddr += 0x100000; paddr += 0x100000; } } void mmu_init() { __asm__( /*设置TTB*/ "ldr r0, =0x30000000\n" "mcr p15, 0, r0, c2, c0, 0\n" /*不进行权限检查*/ "mvn r0, #0\n" "mcr p15, 0, r0, c3, c0, 0\n" /*使能MMU*/ "mrc p15, 0, r0, c1, c0, 0\n" "orr r0, r0, #0x0001\n" "mcr p15, 0, r0, c1, c0, 0\n" : : ); } int gboot_main() { //1.建立页表 2.写入TTB 3.使能MMU create_page_table(); mmu_init(); *(GPBCON) = 0x15400; 此时访问的是虚拟地址GPBCON 0xa000 0010,系统会自动取出来前12位0xa000的值,又由于c2寄存器中TTB的值是0x30000000, 所以对应页表项中0xa000项。又由于该页表项在初始化的时候, *(ttb + (vaddr >> 20)) = (paddr & 0xFFF00000) | MMU_SECDESC,已经写死了一个固定值了。 于是最后访问的就是该写死的值(0x30000000 & 0xFFF00000) | MMU_SECDESC + offset,offset等于0x10 *(GPBDAT) = 0x6BF; return 0; }
Makefile
all: start.o main.o arm-linux-ld -Tgboot.lds -o gboot.elf $^ arm-linux-objcopy -O binary gboot.elf gboot.bin %.o : %.S arm-linux-gcc -g -c $^ %.o : %.c arm-linux-gcc -g -c $^ .PHONY: clean clean: rm *.o *.elf *.bin
start.s
.text .global _start _start: b reset ldr pc, _undifined_instruction ldr pc, _software_interrupt ldr pc, _prefetch_abort ldr pc, _data_abort ldr pc, _not_used ldr pc, _irq ldr pc, _fiq _undifined_instruction: .word undifined_instruction _software_interrupt: .word software_interrupt _prefetch_abort: .word prefetch_abort _data_abort: .word data_abort _not_used: .word not_used _irq: .word irq _fiq: .word reset undifined_instruction: nop software_interrupt: nop prefetch_abort: nop data_abort: nop not_used: nop irq: nop fiq: nop reset: bl set_svc bl disable_watchdog bl disable_interrupt bl disable_mmu bl init_clock bl init_sdram bl copy_to_ram bl init_stack bl clean_bss ldr pc, =gboot_main @ bl light_led set_svc: mrs r0, cpsr bic r0, r0,#0x1f orr r0, r0,#0xd3 msr cpsr, r0 mov pc, lr #define pWTCON 0x53000000 disable_watchdog: ldr r0, =pWTCON mov r1, #0x0 str r1, [r0] mov pc, lr disable_interrupt: mvn r1, #0x0 ldr r0, =0x4a000008 str r1, [r0] mov pc, lr disable_mmu: mcr p15,0,r0,c7,c7,0 mrc p15,0,r0,c1,c0,0 bic r0, r0, #0x00000007 mcr p15,0,r0,c1,c0,0 mov pc, lr #define CLKDIVN 0x4c000014 #define MPLLCON 0x4c000008 #define MPLL_405MHZ ((127<<12)|(2<<4)|(1<<0)) init_clock: ldr r0, =CLKDIVN mov r1, #0x5 str r1, [r0] mcr p15,0,r0,c1,c0,0 orr r0,r0,#0xc0000000 mcr p15,0,r0,c1,c0,0 ldr r0, =MPLLCON ldr r1, =MPLL_405MHZ str r1, [r0] mov pc, lr #define mem_contrl 0x48000000 init_sdram: ldr r0, =mem_contrl add r3, r0, #4*13 adrl r1, mem_data 0: ldr r2, [r1], #4 str r2, [r0], #4 cmp r0, r3 bne 0b mov pc, lr copy_to_ram: ldr r0, =0x0 ldr r1, =0x30008000 add r3, r0, #1024*4 copy_loop: ldr r2, [r0], #4 str r2, [r1], #4 cmp r0, r3 bne copy_loop mov pc, lr init_stack: ldr sp, =0x34000000 mov pc ,lr clean_bss: ldr r0, =bss_start ldr r1, =bss_end cmp r0, r1 moveq pc, lr clean_loop: mov r2, #0 str r2, [r0], #4 cmp r0, r1 bne clean_loop mov pc, lr mem_data: .long 0x22000000 .long 0x00000700 .long 0x00000700 .long 0x00000700 .long 0x00000700 .long 0x00000700 .long 0x00000700 .long 0x00018001 .long 0x00018001 .long 0x008c04f5 .long 0x000000b1 .long 0x00000030 .long 0x00000030 #define GPBCON 0x56000010 #define GPBDAT 0x56000014 light_led: ldr r0, =GPBCON ldr r1,=0x15400 str r1, [r0] ldr r0, =GPBDAT ldr r1,=0x6BF str r1, [r0] mov pc, lr
gboot.lds
OUTPUT_ARCH(arm) ENTRY(_start) SECTIONS { . = 0x30008000; . = ALIGN(4); .text : { start.o (.text) *(.text) } . = ALIGN(4); .data : { *(.data) } . = ALIGN(4); bss_start = .; .bss : { *(.bss) } bss_end = .; }