In fact, it takes a lot of hard work to load and run the kernel of the Android system, because everything is difficult at the beginning. At the beginning of a system, there are no resources to use. The CPU only recognizes the address 0x00000000 and runs the first instruction from there. And this code has a size limit and cannot be very large. Therefore, it is necessary to develop a boot program to run there. In the training course here, the S3C6410 development board is mainly used, and UBoot is used as the boot program (Bootloader). UBoot is a very common boot program, and it is widely used in embedded systems. It is also very powerful. The design architecture is very flexible and very convenient to port to different embedded devices.
As we know from the previous section, ARM CPU is fixed to start running from 0x00000000, so the compiled size of UBoot cannot be placed in the memory space of 0x00000000, so how does UBoot get control? In fact, in S3C6410, different levels can be set through the CPU pins, and you can choose to run the program inside the CPU, and then let this small program load UBoot to the appropriate address to run. So the next question is where is the appropriate address for UBoot? To understand this appropriate address, you need to read the manual of S3C6410. By reading this manual, you will find that the CPU's memory is fixed in two address spaces, as follows:
0x50000000--0x5FFFFFFF, size is 256M
0x60000000--0x6FFFFFFF, size is 256M
From this, we can see that all memory RAM must be placed in this address space, that is, the physical address space, so UBoot must be loaded into this memory space to run. So does UBoot need to know where to run when it is compiled? The answer is yes. When UBoot is running, there is a lot of data that needs to be found to address the memory address. When UBoot is compiled, the following is specified:
TEXT_BASE = 0xc7e00000
Wow, why is the address here 0xc7e00000? Is it wrong? In fact, there is a lot of stuff here. The content related to it is MMU. The so-called MMU is a memory mapping hardware. Its main function is to map the unlimited virtual memory address space to the limited physical memory address space. The function is to reuse the physical memory and facilitate the compilation of all software. From this, we can know that UBoot is compiled to run at the virtual address 0xc7e00000. Before the MMU is turned on, its physical address is 0x57e00000. In fact, it is the same place in terms of physical address.
From the previous we can know that the real physical address of UBoot is 0x57e00000, and the corresponding virtual address is 0xc7e00000. This address is a high-end address relative to 256 memory. Why is it put into this address to run, instead of the physical address of 0x50000000 (the virtual machine address 0xC0000000)? In fact, this is to prepare for the subsequent kernel Linux operation, otherwise they will fight with each other and the whole system will fail. You can see the relevant information from the memory image file compiled by UBoot:
c7e00000T _start
c7e00020t _undefined_instruction
c7e00024t _software_interrupt
c7e00028t _prefetch_abort
c7e0002ct _data_abort
c7e00030t _not_used
c7e00034t _irq
c7e00038t _fiq
c7e0003ct _pad
c7e00040T _end_vect
c7e00040t _TEXT_BASE
c7e00044t _TEXT_PHY_BASE
c7e00048T _armboot_start
c7e0004cT _bss_start
c7e00050T _bss_end
c7e00054t reset
This image file indicates that all start codes are relative to 0xc7e00000, including all data accesses. In the MMU configuration of UBoot, the following code is used to map the physical address 0x50000000 to the virtual address 0xc0000000, as follows:
//128MB for SDRAM 0xC0000000 -> 0x50000000
.set__base, 0x500
.rept0xD00 - 0xC00
FL_SECTION_ENTRY__base,3,0,1,1
.set__base,__base+1
.endr
The boot program is loaded and run, and after it is fully prepared, the kernel can be loaded and run. The kernel address is also particular. Generally, the Linux kernel needs to be loaded at the physical address 0x50008000, so the virtual address is 0xc0008000, so the kernel can be loaded and run at the low end, and the high end address can be used for all applications to run.
To summarize, the CPU starts running the Flash program from 0x00000000, then relocates UBoot to the physical address 0x57e00000 (virtual address 0xc7e00000) to run, then turns on the MMU, which corresponds to running at the virtual address 0xc7e00000, then loads the kernel to the virtual address 0xc0008000 (physical address 0x50008000), and then jumps to this address to run. Therefore, UBoot must specify the virtual address 0xc7e00000 as the base address to connect to the program.
The following is a code snippet of UBoot loading the kernel and running it:
voiddo_bootm_linux (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[],
ulong addr, ulong *len_ptr, intverify)
{
#ifdefCONFIG_CMDLINE_TAG
char *commandline = getenv("bootargs"); //Get kernel boot parameters
#endif
theKernel = (void (*)(int, int,uint))ntohl(hdr->ih_ep); //The kernel entry address specified in mkimage.c
/*
* Check if there is an initrd image
*/
if (argc >= 3){//Detect initrd temporary file system, including: magicnumber, CRC check of header and data, similar to the previous one
SHOW_BOOT_PROGRESS (9);
addr = simple_strtoul (argv[2], NULL, 16); //Get the address of initrd, the following detection process is similar to the kernel
}
if (data) {
initrd_start = data;
initrd_end = initrd_start + len;
}
//Start passing parameters to the kernel
#ifdefined (CONFIG_SETUP_MEMORY_TAGS) ||
defined (CONFIG_CMDLINE_TAG) ||
defined (CONFIG_INITRD_TAG) ||
defined (CONFIG_SERIAL_TAG) ||
defined (CONFIG_REVISION_TAG) ||
defined (CONFIG_LCD) ||
defined (CONFIG_VFD)
setup_start_tag (bd);
#ifdefCONFIG_SERIAL_TAG
setup_serial_tag (¶ms);
#endif
#ifdefCONFIG_REVISION_TAG
setup_revision_tag (¶ms);
#endif
#ifdefCONFIG_SETUP_MEMORY_TAGS
setup_memory_tags (bd);
#endif
#ifdefCONFIG_CMDLINE_TAG
setup_commandline_tag (bd, commandline);
#endif
#ifdefCONFIG_INITRD_TAG
if (initrd_start && initrd_end)
setup_initrd_tag (bd, initrd_start,initrd_end);
#endif
#ifdefined (CONFIG_VFD) || defined (CONFIG_LCD)
setup_videolfb_tag ((gd_t *) gd);
#endif
setup_end_tag (bd);
#endif
/* we assume that the kernel is in place */
printf ("nStarting kernel ...nn");
cleanup_before_linux (); //Settings required before starting the kernel
theKernel (0, bd->bi_arch_number, bd->bi_boot_params); //Start the kernel, and the uboot mission is now complete.
}
Previous article:ARM - Stack
Next article:Developing an Android driver that can count words (3)
Recommended ReadingLatest update time:2024-11-22 12:33
- Naxin Micro and Xinxian jointly launched the NS800RT series of real-time control MCUs
- How to learn embedded systems based on ARM platform
- Summary of jffs2_scan_eraseblock issues
- Application of SPCOMM Control in Serial Communication of Delphi7.0
- Using TComm component to realize serial communication in Delphi environment
- Bar chart code for embedded development practices
- Embedded Development Learning (10)
- Embedded Development Learning (8)
- Embedded Development Learning (6)
Professor at Beihang University, dedicated to promoting microcontrollers and embedded systems for over 20 years.
- Intel promotes AI with multi-dimensional efforts in technology, application, and ecology
- ChinaJoy Qualcomm Snapdragon Theme Pavilion takes you to experience the new changes in digital entertainment in the 5G era
- Infineon's latest generation IGBT technology platform enables precise control of speed and position
- Two test methods for LED lighting life
- Don't Let Lightning Induced Surges Scare You
- Application of brushless motor controller ML4425/4426
- Easy identification of LED power supply quality
- World's first integrated photovoltaic solar system completed in Israel
- Sliding window mean filter for avr microcontroller AD conversion
- What does call mean in the detailed explanation of ABB robot programming instructions?
- Vicor high-performance power modules enable the development of low-altitude avionics and EVTOL
- Chuangshi Technology's first appearance at electronica 2024: accelerating the overseas expansion of domestic distributors
- Chuangshi Technology's first appearance at electronica 2024: accelerating the overseas expansion of domestic distributors
- "Cross-chip" quantum entanglement helps build more powerful quantum computing capabilities
- Ultrasound patch can continuously and noninvasively monitor blood pressure
- Ultrasound patch can continuously and noninvasively monitor blood pressure
- Europe's three largest chip giants re-examine their supply chains
- Europe's three largest chip giants re-examine their supply chains
- Breaking through the intelligent competition, Changan Automobile opens the "God's perspective"
- The world's first fully digital chassis, looking forward to the debut of the U7 PHEV and EV versions
- New Edition of Electrical Control and PLC Application Technology
- Notes on Foobar2000 APE Splitting
- Op amp circuit waveform analysis problem
- [GD32E231 DIY Contest]——08. Solution to using JLINK to debug and download GD32E231
- Recruiting hardware test engineers Annual salary: 200,000-500,000 | Experience: more than 5 years | Work location: Shenzhen
- Supercapacitor balancing circuit
- Measurement of the impact of electrical equipment on power supply quality
- When should you choose DC/DC and when should you choose LDO?
- Share: TI headphone amplifier positive and negative voltage design
- EEWORLD University Hall ---- Digital Image Processing Tianjin University of Technology