u-boot transplantation (8)---code modification---storage controller--MMU

Publisher:zhuanshiLatest update time:2023-07-03 Source: elecfansKeywords:u-boot Reading articles on mobile phones Scan QR code
Read articles on your mobile phone anytime, anywhere

1. Introduction to MMU

1.1 Virtual address and physical address

  Build two applications, hello1.c and hello2.c, and then run:

  hello1.c

  

  hello2.c

  

  The running results are as follows:

  

   You can see that the addresses printed by the two results are the same, both are 0x601040, which means that both programs are running at the same address. Our infinite loop program ensures that the two programs are running at the same time.

   

  For 2440, as shown below:

  

  The CPU only issues addresses and reads and writes data. It doesn't matter whether the address is a physical address or a virtual address.

  When writing a program, the link address does not have a physical address or a virtual address. The link address is what the CPU sees, from the CPU's perspective.

1.2 Convert virtual address to physical address

  For ARM, the virtual address (VA) is converted into a physical address (PA) through a table. This table is the page table.

  The simple steps to set up the mapping are:

  • Create a table: virtual address to physical address mapping

  • Tell the MMU the table address: the table is in memory, tell the MMU the first address of the table

  • Start MMU  

2. Code

2.1 start.S (archarmcpuarm920t) 

  The cpu_init_crit in start.S enables the MMU. When u-boot starts, the MMU is not enabled. The enabling of MMU involves the CP15 coprocessor.

  The code snippet is as follows:

 1 /*

 2 * disable MMU stuff and caches

 3*/

 4 mrc p15, 0, r0, c1, c0, 0 /* Read the value of register C1 of CP15 into r0*/

 5 /* Bits 8, 9, and 13 of the C1 register are cleared

 6 * S (bit[8]) In MMU-based storage systems, this bit is used for system protection

 7 * R (bit[9]) In MMU-based storage systems, this bit is used for ROM protection

 8*V(bit[13])

 9 * For systems that support high-end exception vector tables, this control bit controls the location of the vector table

10 * 0: Select the low-end exception interrupt vector 0x0~0x1c 

11 * 1: Select the high-end exception interrupt vector 0xffff0000~ 0xffff001c

12 * For systems that do not support high-end exception vector tables, this bit returns 0 when reading and ignores when writing.

13 */

14 bic r0, r0, #0x00002300 @ clear bits 13, 9:8 (--V- --RS)

15 /* Bits 0, 1, 2, and 7 of the C1 register are cleared

16*M(bit[0])

17 * 0: Disable MMU or PU 

18 * 1: Enable MMU or PU

19 * If there is no MMU and PU in the system, this bit returns 0 when reading and ignores this bit when writing.

20*A(bit[1])

21 * 0: Disable address alignment check

22 * 1: Enable address alignment check

23*C(bit[2])

24 * When the data cache and instruction cache are separated, this control bit disables/enables the data cache.

25 * When the data cache and instruction cache are unified, this control bit disables/enables the entire cache.

26 * 0: prohibit data/entire cache 

27 * 1: enable data/entire cache

28 * If there is no cache in the system, this bit returns 0 when reading. Ignore when writing.

29 * When the cache cannot be disabled in the system, 1 is returned when reading and ignored when writing.

30*B(bit[7])

31 * For ARM systems whose storage system supports both big-endian and little-endian, this control bit configures the storage mode of the system.

32 * 0: little endian  

33 * 1: big endian

34 * For systems that only support little-endian, this bit returns 0 when reading and ignores when writing.

35 * For systems that only support big-endian, this bit returns 1 when reading and ignores when writing.

36 */

37 bic r0, r0, #0x00000087 @ clear bits 7, 2:0 (B--- -CAM)

38 /* Bit1 of the C1 register is set to 1, which enables address alignment*/

39 orr r0, r0, #0x00000002 @ set bit 1 (A) Align

40 /* Set bit12 of the C1 register to 1 to enable the instruction cache */

41 /* I (bit[12])

42 * When the data cache and instruction cache are separated, this control bit disables/enables the instruction cache.

43 * 0: Disable instruction cache  

44 * 1: Enable instruction cache

45 * If a unified instruction cache and data cache are used in the system or there is no cache in the system, 0 will be returned when reading this bit and ignored when writing.

46 * When the instruction cache in the system cannot be disabled, this bit returns 1 when reading and ignores when writing.

47 */

48 orr r0, r0, #0x00001000 @ set bit 12 (I) I-Cache

49 mcr p15, 0, r0, c1, c0, 0 /* Write the value of r0 to register C1 of CP15*/

50 

51/*

52 * before relocating, we have to setup RAM timing

53 * because memory timing is board-dependent, you will

54 * find a lowlevel_init.S in your board directory.

55 */

56 mov ip, lr /* Save the function address for return */

  Afterwards, the code in start.S will enter _main (crt0.S (archarmlib)) to run.


2.2 crt0.S (archarmlib)

  Run the _main function in ctr0.S. In this function, run to board_init_f (initialization before board startup), and then execute to the linked list init_sequence_f, where the MMU is initialized reserve_mmu.


2.2.1 reserve_mmu


 1 static int reserve_mmu(void)

 2 {

 3 /* reserve TLB table */

 4 gd->arch.tlb_size = PGTABLE_SIZE; //PGTABLE_SIZE = 4096 *4 Reserve 16kb MMU page table

 5 gd->relocaddr -= gd->arch.tlb_size;//gd->relocaddr = gd->relocaddr - 16K = 0x33ffc000

 6 

 7 /* round down to next 64 kB limit */

 8 gd->relocaddr &= ~(0x10000 - 1);//64kb alignment gd->relocaddr = 0x33ff0000

 9 

10 gd->arch.tlb_addr = gd->relocaddr;//gd->arch.tlb_addr = 0x33ff0000

11 debug("TLB table from %08lx to %08lxn", gd->arch.tlb_addr,

12 gd->arch.tlb_addr + gd->arch.tlb_size);

13 return 0;

14}

  We can get the size of PGTABLE_SIZE by looking at u-boot.dis:

  

  The first line is the size of PGTABLE_SIZE.

  After executing the linked list, jump back to _main to continue execution, and then execute to board_init_r (Board_r.c (common) initialization code after board startup).

  A linked list, init_sequence_r, will also be executed in board_init_r. Execute various initialization functions in the linked list, and then execute them in board_init. In board_init, perform icache_enable and dcache_enable.

  Both functions call the cache_enable function. There are MMU settings in it.

2.2.2 cache_enable 

  cache_enable

 1 static void cache_enable(uint32_t cache_bit)

 2 {

 3 uint32_t reg;

 4 

 5 /* The data cache is not active unless the mmu is enabled too */

 6 if ((cache_bit == CR_C) && !mmu_enabled())

 7 mmu_setup();

 8 reg = get_cr(); /* get control reg. */

 9 cp_delay();

10 set_cr(reg | cache_bit);

11 }


  Now let’s look at the mmu_setup function


 1 /* to activate the MMU we need to set up virtual memory: use 1M areas */

 2 static inline void mmu_setup(void)

 3 {

 4 int i;

 5 u32 reg;

 6 

 7 arm_init_before_mmu(); //Empty function

 8 /* Set up an identity-mapping for all 4GB, rw for everyone */

 9 for (i = 0; i < 4096; i++)

10 set_section_dcache(i, DCACHE_OFF); //Pass in the DCACHE_OFF parameter and establish the page table address

11 

12 for (i = 0; i < CONFIG_NR_DRAM_BANKS; i++) {

13 dram_bank_mmu_setup(i); //Set the page table size and address of DRAM

14}

15 

16 /* Set the access control to all-supervisor */

17 asm volatile("mcr p15, 0, %0, c3, c0, 0"

18 : : "r" (~0)); //MMU initializes

19 

20 arm_init_domains(); //Empty function

twenty one 

22 /* and enable the mmu */

23 reg = get_cr(); /* get control reg. */

24 cp_delay();

25 set_cr(reg | CR_M);

26}

27 

28 arch/arm/include/asm/system.h

29 /* Size of an MMU section */

30 enum {

31 MMU_SECTION_SHIFT = 20,

32 MMU_SECTION_SIZE = 1 << MMU_SECTION_SHIFT,

33};

34 

35 /* Page table creation function, each page is 1M, the starting address of the page is section */

36 void set_section_dcache(int section, enum dcache_option option)

37 {

38 u32 *page_table = (u32 *)gd->arch.tlb_addr; //Take out page_table, 16K

39 u32 value;

40 

41 value = (section << MMU_SECTION_SHIFT) | (3 << 10); //The 20th power of 2 is 1M

42 value |= option;

43 page_table[section] = value;

44}

45 

46 __weak void dram_bank_mmu_setup(int bank)

47 {

48 bd_t *bd = gd->bd;

49 int i;

50 

51 debug("%s: bank: %dn", __func__, bank);

52 for (i = bd->bi_dram[bank].start >> 20;

53 i < (bd->bi_dram[bank].start >> 20) + (bd->bi_dram[bank].size >> 20);

54 i++) {

55 

56 set_section_dcache(i, DCACHE_WRITETHROUGH);

57 }

58 }


Keywords:u-boot Reference address:u-boot transplantation (8)---code modification---storage controller--MMU

Previous article:u-boot transplantation (9)---Code modification---NAND
Next article:u-boot transplantation (7)---code modification---storage controller

Recommended ReadingLatest update time:2024-11-15 14:51

Chapter 2: Tiny4412 U-BOOT transplantation and boot analysis
1. Startup Process Description  Let's talk about the startup process. The first source is to turn on the power. I believe everyone knows this. After the CPU is powered on, the SP pointer points to 0x0000_0000, and the first instruction is taken from this address. But at this time: PLL is not started, and the CPU opera
[Microcontroller]
Chapter 2: Tiny4412 U-BOOT transplantation and boot analysis
Some supplements on debugging exynos 4412 u-boot with jLink V8
/** ****************************************************************************** * @author Maoxiao Hu * @version V1.0.0 * @date Dec-2014 ****************************************************************************** * COPYRIGHT 2014 ISE of SHANDONG UNIVERSITY *******************************************************
[Microcontroller]
Some supplements on debugging exynos 4412 u-boot with jLink V8
S3C6410 porting u-boot-2010.3 (5) Dnw for linux
Now start recording the installation of dnw function on Linux If you want the source code, you can fork it here https://github.com/Qunero/dnw4linux The detailed usage is clearly explained in README, so I won’t go into details here. Here I will just talk about how to use it
[Microcontroller]
The reason why S3C2440 cannot enter interrupt without MMU_Init
After struggling for an afternoon, I finally figured it out. The so-called MMU (virtual memory management unit) is nothing more than converting physical addresses into virtual addresses. As for the so-called physical address, everyone who uses STM32 knows that its RAM starts at 0x20000000 and ROM starts at 0x8000000. T
[Microcontroller]
Share tiny4412, emmc burning u-boot, support fastboot mode burning emmc
Preface: Compiling and burning U-boot according to the CD introduction cannot start the board. Only after using superboot can the board be started. At this point, I guess many people think the same as I do, how to use the open source u-boot to start the development board. Let's get back to the point. Our goal is to u
[Microcontroller]
Chapter 7: Tiny4412 U-BOOT transplantation DDR memory configuration
Last time, we finished talking about the low-level initialization of Nand Flash. The operation of Nand Flash is mainly in board_init_f_nand(), which involves copying the code from Nand Flash to DDR. This will be analyzed in the actual transplantation process later in combination with the source code flow. Normally, DD
[Microcontroller]
Chapter 7: Tiny4412 U-BOOT transplantation DDR memory configuration
U-boot porting on mini2440-S3C2440 (1) - Development environment setup - Cross-compilation toolchain installation
When compiling U-boot for mini2440, to compile an executable file -bin that can be used on the ARM platform, you must first install the cross-compilation tool chain in Ubuntu. Because I use the development board of Friendly Arm, I use the tool chain that has been made. Of course, you can also make your own tool chain:
[Microcontroller]
U-boot porting on mini2440-S3C2440 (1) - Development environment setup - Cross-compilation toolchain installation
3. Configuration and use of MMU
In the previous basic knowledge, physical addresses were used to light up the LED lights. Now, after learning about MMU, we will use the knowledge of MMU to light up the LED lights with virtual addresses. In addition, MMU was turned off before, so we have to turn it on to use it next. As we learned in the previ
[Microcontroller]
3. Configuration and use of MMU
Latest Microcontroller Articles
Change More Related Popular Components

EEWorld
subscription
account

EEWorld
service
account

Automotive
development
circle

About Us Customer Service Contact Information Datasheet Sitemap LatestNews


Room 1530, 15th Floor, Building B, No.18 Zhongguancun Street, Haidian District, Beijing, Postal Code: 100190 China Telephone: 008610 8235 0740

Copyright © 2005-2024 EEWORLD.com.cn, Inc. All rights reserved 京ICP证060456号 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号