MMU initialization and enabling experiments

Source: Internet
Author: User

The memory management unit MMU is responsible for ing virtual addresses to physical addresses, and provides a hardware mechanism for memory access permission check.

Four types of ing lengths: segment (1 MB), large page (64 KB), small page (4 kb), and extremely small page (1 kb ).

You can set access permissions for each segment.

Each subpage (sub-page, that is, 1/4 of the mapped page) of a large page or a small page can be set with access permissions.

When MMU is not started, all components such as CPU core, cache, MMU, and peripherals use physical addresses.

I will not write more theoretical knowledge. After all, this experiment is not about the principle, but the comments of the code will be very clear.

Main C code:

 

View plaincopy to clipboardprint?
  1. # Include "memmap. H"
  2. Void creat_page_table ()
  3. {
  4. // We can establish a segment descriptor which is easier to understand.
  5. // The permission settings make them 12bit lower than the descriptor [11-0]
  6. # Define mmu_ap (3 <10) // AP bit 111 access permission
  7. # Define mmu_domain (0 <5) // select the 0 domain
  8. # Define mmu_special (1 <4) // must be 1 Why?
  9. # Define mmu_cacheen (1 <3) // cache enabling
  10. # Define mmu_buffen (1 <2) // buffer enabling
  11. # Define mmu_section 2 // 0b10 indicates that this is a segment descriptor.
  12. // The cache and buff are not enabled for 12 bit low segment descriptors because it will be used for ing of the first 1 m and cannot be enabled
  13. # Define mmu_sec_desc mmu_ap | mmu_domain | mmu_special | mmu_section
  14. // Enable cache and buff at 12 Bit lower segment descriptor, which will be used for the later SDRAM ing and enable cache buffer
  15. # Define mmu_sec_desc_wb mmu_ap | mmu_domain | mmu_special | mmu_section | mmu_cacheen | mmu_buffen
  16. Unsigned long vir_address, phy_address;
  17. Unsigned long * mmu_table_base = (unsigned long *) 0x30000000; // The address is converted to a pointer.
  18. // Map the first 1 m physical address to the first 1 m of the virtual address. In order to be able to execute the program within the first 4 K of the 0 address after MMU is enabled, so they are a one-to-one correspondence.
  19. /*
  20. (Vir_address> 20. You can understand that the virtual address is 12 bits in height, or the virtual address is in addition to 1 MB, and the segment address is obtained, therefore, the virtual address to be mapped must be a multiple of 1 m. If you have learned the assembly, you should easily know how the segment address is. For example, if we use 1 m segments here, Segment 1 is 1 m = 0x100000. Segment, large page, small page address, that is, the unit is different.
  21. Phy_address & 0xfff00000 is also the result of storing 12bit high, which is a multiple of 1 MB. It is also the physical address corresponding to the segment. It has 12bit lower storage permission and 8bit in the middle is retained.
  22. */
  23. Vir_address = 0;
  24. Phy_address = 0;
  25. * (Mmu_table_base + (vir_address> 20) = (phy_address & 0xfff00000) | mmu_sec_desc );
  26. /*
  27. Mmu_table_base + (vir_address> 20) Get the segment descriptor address (pointer). These four segments store a 32bit segment descriptor (phy_address & 0xfff00000) | mmu_sec_desc), the [31-20] bit of the segment descriptor stores the physical address of the segment (the unit is the actual address, such as 12 m, 12 m = 0x1200000)
  28. Mmu_sec_desc is the permission defined above.
  29. */
  30. /* Map 1 m after 0x56000000 to 0xa0000000
  31. External I/O storage devices cannot enable cache and buff.
  32. */
  33. Vir_address = 0xa0000000;
  34. Phy_address = 0x56000000;
  35. * (Mmu_table_base + (vir_address> 20) = (phy_address & 0xfff00000) | mmu_sec_desc );
  36. /* Map 64 m after 0x30000000 to 0xb0000000 */
  37. Vir_address = 0xb0000000;
  38. Phy_address = 0x30000000;
  39. While (phy_address <0 x34000000)
  40. {
  41. * (Mmu_table_base + (vir_address> 20) = (phy_address & 0xfff00000) | mmu_sec_desc_wb );
  42. Vir_address + = 0x100000; // accumulate 1 m to the next segment descriptor
  43. Phy_address + = 0x100000;
  44. }
  45. }
  46. /* The above is the descriptor table we created, but the CPU still does not know what is going on. Next we need to tell the CPU such a virtual address ing physical address rule, because all virtual address conversions after MMU is enabled */
  47. Void mmu_init ()
  48. {
  49. Unsigned long TTB = 0x30000000; // the header address of the Descriptor Table
  50. _ ASM __(
  51. "Mov r0, #0/N" // operator coprocessor needs to carefully read its structure
  52. "MCR P15, 0, R0, C7, C7, 0/N" // MCR writes R0 to C7
  53. "MCR P15, 0, R0, C7, C10, 4/N"
  54. "MCR P15, 0, R0, C8, C7, 0/N"
  55. "Mov R4, % 0/N"
  56. "MCR P15, 0, R4, C2, C0, 0/N"
  57. "MVN r0, #0/N"
  58. "MCR P15, 0, R0, C3, C0, 0/N"
  59. /* Read and modify the value of the control register before saving it */
  60. "MRC P15, 0, R0, C1, C0, 0/N"
  61. /* Clear unnecessary bits first. If necessary, set them again */
  62. "Bic r0, R0, #0x3000/N"
  63. "Bic r0, R0, #0x0300/N"
  64. "Bic r0, R0, #0x0087/N" // clear 1 2 3 7bit
  65. /* Set the required bit */
  66. "Orr r0, R0, #0x2/N" // enable alignment check
  67. "Orr r0, R0, #0x4/N" // enable dcache
  68. "Orr r0, R0, #0x1000/N" // enable icache
  69. "Orr r0, R0, #0x1/N" // enable MMU
  70. "MCR P15, 0, R0, C1, C0, 0/N"
  71. :
  72. : "R" (TTB)
  73. );
  74. }

# Include "memmap. H "Void creat_page_table () {// It is relatively easy for us to create segment descriptors. // The permission setting is 12bit lower than the descriptor [11-0] # define mmu_ap (3 <10) // AP bit 111 access permission # define mmu_domain (0 <5) // select 0 domain # define mmu_special (1 <4) // must be 1 Why? # Define mmu_cacheen (1 <3) // cache enabling # define mmu_buffen (1 <2) // buffer enabling # define mmu_section 2 // 0b10 indicates that the cache and buff are not enabled because the segment descriptor is 12bit low because it will be used for ing of the first 1 MB, you cannot enable cache # define mmu_sec_desc mmu_ap | mmu_domain | mmu_special | mmu_section // enable cache and buff at 12bit lower segment descriptor, which will be used for the subsequent SDRAM ing, enable cache buffer # define mmu_sec_desc_wb mmu_ap | mmu_domain | mmu_special | mmu_section | mmu_cacheen | mmu_buffen unsigned long vir_address, pH Y_address; unsigned long * mmu_table_base = (unsigned long *) 0x30000000; // The address is converted to the pointer // The first 1 m physical address mapped to the first 1 m of the virtual address, in order to be able to execute programs in the first 4 K with 0 addresses after MMU is enabled, therefore, they are a one-to-one correspondence relationship/* (vir_address> 20 can be understood as a virtual address with a height of 12 bits or a virtual address with a segment address in addition to 1 MB, therefore, the virtual address to be mapped must be a multiple of 1 m. If you have learned the assembly, you should easily know what the segment address is. For example, if we use 1 m segments, Segment 1 is 1 m = 0x100000. Segment, large page, small page address, that is, the unit is different. Phy_address & 0xfff00000 is also the result of storing 12bit high, which is a multiple of 1 MB. It is also the physical address corresponding to the segment. It has a low storage permission of 12bit, And the 8bit in the middle is retained */vir_address = 0; phy_address = 0; * (mmu_table_base + (vir_address> 20) = (phy_address & 0xfff00000) | mmu_sec_desc);/* mmu_table_base + (vir_address> 20) get the segment descriptor address (pointer). These four bytes hold a 32bit segment descriptor (phy_address & 0xfff00000) | mmu_sec_desc )), the [31-20] bit of the segment descriptor stores the physical address of the segment (the unit is the actual address, such as 12 m, 12 m = 0x1200000) mmu_sec_desc is the permission defined above * // * ing 1 m after 0x56000000 to 0xa0000000 external IO Storage Device is also unable to enable cache and buff */vir_address = 0xa0000000; phy_address = 0x56000000; * (mmu_table_base + (vir_address> 20) = (phy_address & 0xfff00000) | mmu_sec_desc ); /* map 64 m after 0x30000000 to 0xb0000000 */vir_address = 0xb0000000; phy_address = 0x30000000; while (phy_address <0x34000000) {* (mmu_table_base + (vir_address> 20) = (phy_address & 0xfff00000) | mmu_sec_desc_wb); vir_address + = 0x100000; // accumulate 1 m, the descriptor phy_address + = 0x100000;}/* above is the descriptor table we created, but the CPU still does not know what is going on, next we need to tell the CPU such a virtual address ing physical address rule, because the processing after enabling MMU all the virtual address conversion */void mmu_init () {unsigned long TTB = 0x30000000; // header address of the Descriptor Table _ ASM _ ("mov r0, #0/N "// The operating coprocessor has to carefully read its structure:" MCR P15, 0, R0, C7, C7, 0/N "// MCR writes R0 to C7" MCR P15, 0, R0, C7, C10, 4/N "" MCR P15, 0, R0, C8, c7, 0/N "" mov R4, % 0/N "" MCR P15, 0, R4, C2, C0, 0/N "" MVN r0, #0/N "" MCR P15, 0, R0, C3, C0, 0/N "/* read the value of the control register and modify it. */" MRC P15, 0, R0, C1, C0, 0/N "/* clear unnecessary bits first. If necessary, set */" Bic r0, R0, #0x3000/N "" Bic r0, R0, #0x0300/N "" Bic r0, R0, #0x0087/N "// clear 1 2 3 7bit/* set the required bit */" Orr r0, r0, #0x2/N "// enable alignment check" Orr r0, R0, #0x4/N "// enable dcache" Orr r0, R0, #0x1000/N "// enable icache" Orr r0, R0, #0x1/N "// enable MMU" MCR P15, 0, R0, C1, c0, 0/N ":" R "(TTB ));}

I am also vague about the structure of the coprocessor.

The second step is to define the physical addresses of those registers, because after MMU is enabled, only virtual addresses are recognized.

View plaincopy to clipboardprint?
  1. // Led fanction
  2. # Define gpbcon (* (volatile unsigned long *) 0xa0000010) // convert the address value to a pointer first, and gpbcon is actually the value stored in this address. Haha
  3. # Define gpbdat (* (volatile unsigned long *) 0xa0000014)
  4. # Define gpbup (* (volatile unsigned long *) 0xa0000018)
  5. // Key ADDR
  6. # Define gpfcon (* (volatile unsigned long *) 0xa0000050)
  7. # Define gpfdat (* (volatile unsigned long *) 0xa0000054)
  8. # Define gpfup (* (volatile unsigned long *) 0xa0000058)

// Led fanction # define gpbcon (* (volatile unsigned long *) 0xa0000010) // first convert the address value to a pointer, gpbcon is actually the value stored in this address. Haha # define gpbdat (* (volatile unsigned long *) 0xa0000014) # define gpbup (* (volatile unsigned long *) 0xa0000018) // key ADDR # define gpfcon (* (volatile unsigned long *) 0xa0000050) # define gpfdat (* (volatile unsigned long *) 0xa0000054) # define gpfup (* (volatile unsigned long *) 0xa0000058)

Then there is a bit of content added by START. S.

View plaincopy to clipboardprint?
  1. @ Led start
  2. @ 2010-01-12
  3. @ Jay
  4. . Globl _ start
  5. _ Start:
  6. B Reset
  7. @ Reserved extended interrupt vector table
  8. Reset:
  9. /* Because the following C function requires an SP */
  10. LDR sp, = 4096
  11. @ Disable Watchdog
  12. LDR r0, = 0x53000000
  13. MoV R1, #0
  14. STR R1, [R0]
  15. @ Init SDRAM
  16. BL memsetup
  17. @ Brief the code to SDRAM
  18. BL cp_to_sdram
  19. @ Setup pagetable
  20. BL creat_page_table
  21. @ Init and enable MMU
  22. BL mmu_init
  23. @ Reset stack MMU is enabled. We need to reset the next stack pointer to point to the top of the virtual address ing.
  24. LDR sp, = 0xb4000000
  25. @ Jump to the virtual address
  26. /* These two commands are based on uboot's understanding of this point. _ led_on is a tag, and the tag is actually an address, the content stored by this tag is another tag led_test (is it quite familiar? By the way, it is the pointer of the C language), in fact, it is to assign the _ led_on content led_text to the PC */
  27. Ldr pc, _ led_on
  28. _ Led_on:. Word led_test
  29. Load_sd:
  30. LDR sp, = 0x34000000
  31. BL led_test
  32. @ Copy to SDRAM
  33. Cp_to_sdram:
  34. @ ADR r0, _ start
  35. MoV r0, #0
  36. Add R1, R0, #4096
  37. LDR R2, = 0x30004000 @ note that 0x30000000 is not specified here
  38. LP:
  39. Ldmia R0 !, {R3-r11}
  40. Stmia R2 !, {R3-r11}
  41. CMP r0, r1
  42. Ble lp
  43. MoV PC, LR

@ Led start @ 2010-01-12 @ Jay. globl _ start: B reset @ reserved future extended interrupt vector table Reset:/* because the following C functions need to set up sp */LDR sp, = 4096 @ disable watchdog LDR r0, = 0x53000000 mov R1, #0 STR R1, [R0] @ init sdram bl memsetup @ encode the code to sdram bl cp_to_sdram @ setup pagetable BL creat_page_table @ init and enable mmu bl mmu_init @ reset stack MMU is enabled, we need to reset the next stack pointer, pointing to the ldr sp at the top of the virtual address ing, = 0xb4000000 @ jump to the virtual address/*. These two instructions are learned from uboot to pay attention to this point. , _ Led_on is a tag, and the tag is actually an address. The content stored by this tag is another tag led_test (is it quite familiar? By the way, it is the pointer of the C language), in fact, it is to assign the _ led_on content led_text to the PC */ldr pc, _ led_on :. word led_test load_sd: LDR sp, = 0x34000000 BL led_test @ copy to SDRAM cp_to_sdram: @ ADR r0, _ start mov r0, #0 add R1, R0, #4096 LDR R2, = 0x30004000 @ note that Lp: ldmia R0 is not specified here for 0x30000000 !, {R3-r11} stmia R2 !, {R3-r11} CMP r0, R1 ble LP mov PC, LR

The connection script is used.

View plaincopy to clipboardprint?
  1. Output_format ("elf32-littlearm", "elf32-littlearm", "elf32-littlearm ")
  2. Output_arch (ARM)
  3. Entry (_ start)
  4. Sections
  5. {
  6. . = 0x30004000;
  7. . = Align (4 );
  8. . Text:
  9. {
  10. Start. O (. Text)
  11. Low_init.o (. Text)
  12. * (. Text)
  13. }
  14. . = Align (4 );
  15. . Data: {* (. Data )}
  16. . = Align (4 );
  17. . Rodata: {* (. rodata )}
  18. . = Align (4 );
  19. _ Bss_start = .;
  20. . BSS: {* (. BSS )}
  21. _ End = .;
  22. }

Output_format ("elf32-littlearm", "elf32-littlearm", "elf32-littlearm") output_arch (ARM) entry (_ start) Sections {. = 0x30004000 ;. = align (4 );. text: {start. O (. text) low_init.o (. text )*(. text )}. = align (4 );. data :{*(. data )}. = align (4 );. rodata :{*(. rodata )}. = align (4); _ bss_start = .;. BSS :{*(. BSS)} _ end = .;}

This is also learned from uboot.

Align (4) is 4-byte align. 32bitcpu processes 32bit at a time.

It refers to the Knowledge compilation address specified in the current address, which is different from the running address.

The two. commands must be separated by;. = 0x30004000. There is a space here. Otherwise, an error will occur.

Makefile

View plaincopy to clipboardprint?
  1. Cc = arm-Linux-gcc
  2. LD = arm-Linux-LD
  3. CP = arm-Linux-objcopy
  4. Dp = arm-Linux-objdump
  5. Objs: = start. O low_init.o memmap. O led. o
  6. MMU. Bin: $ (objs)
  7. $ (LD)-tboot. LDS-g-o mmu_elf $ ^
  8. $ (CP)-O Binary-s mmu_elf $ @
  9. $ (DP)-D-M arm mmu_elf> MMU. ASM
  10. # Makefile Note:. s cannot be capitalized-t cannot be small-
  11. %. O: %. c
  12. $ (CC)-g-wall-c-o $ @ $ <
  13. %. O: %. s
  14. $ (CC)-g-wall-c-o $ @ s <
  15. Clean:
  16. Rm-f *. ASM *. Bin * _ elf *. o

Cc = arm-Linux-gcc ld = arm-Linux-ld cp = arm-Linux-objcopy dp = arm-Linux-objdump objs: = start. O low_init.o memmap. O led. o mmu. bin: $ (objs) $ (LD)-tboot. LDS-g-o mmu_elf $ ^ $ (CP)-O Binary-s mmu_elf $ @ $ (DP)-D-M arm mmu_elf> MMU. ASM # makefile note. s cannot be capitalized-t cannot be less-%. o: %. C $ (CC)-g-wall-c-o $ @ $ <%. o: %. S $ (CC)-g-wall-c-o $ @ s <clean: Rm-f *. ASM *. bin * _ elf *. O

Although there is not much content, it takes me a lot of time to understand it. Other codes are not changed as before.

Finally, MMU can be successfully enabled.

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.