| .. SPDX-License-Identifier: GPL-2.0-or-later | |
| Memory Management | |
| ================= | |
| .. note:: | |
| This information is outdated and needs to be updated. | |
| U-Boot runs in system state and uses physical addresses, i.e. the | |
| MMU is not used either for address mapping nor for memory protection. | |
| The available memory is mapped to fixed addresses using the | |
| memory-controller. In this process, a contiguous block is formed for each | |
| memory type (Flash, SDRAM, SRAM), even when it consists of several | |
| physical-memory banks. | |
| U-Boot is installed in XIP flash memory, or may be loaded into a lower region of | |
| RAM by a secondary program loader (SPL). After | |
| booting and sizing and initialising DRAM, the code relocates itself | |
| to the upper end of DRAM. Immediately below the U-Boot code some | |
| memory is reserved for use by malloc() [see CONFIG_SYS_MALLOC_LEN | |
| configuration setting]. Below that, a structure with global Board-Info | |
| data is placed, followed by the stack (growing downward). | |
| Additionally, some exception handler code may be copied to the low 8 kB | |
| of DRAM (0x00000000 ... 0x00001fff). | |
| So a typical memory configuration with 16 MB of DRAM could look like | |
| this:: | |
| 0x0000 0000 Exception Vector code | |
| : | |
| 0x0000 1fff | |
| 0x0000 2000 Free for Application Use | |
| : | |
| : | |
| : | |
| : | |
| 0x00fb ff20 Monitor Stack (Growing downward) | |
| 0x00fb ffac Board Info Data and permanent copy of global data | |
| 0x00fc 0000 Malloc Arena | |
| : | |
| 0x00fd ffff | |
| 0x00fe 0000 RAM Copy of Monitor Code | |
| ... eventually: LCD or video framebuffer | |
| ... eventually: pRAM (Protected RAM - unchanged by reset) | |
| 0x00ff ffff [End of RAM] | |
| System RAM Utilization in U-Boot in ARM | |
| --------------------------------------- | |
| Let us break down the relevant parts of the execution sequence where system RAM | |
| comes into play. Please note that these are individual pieces of the entire | |
| boot sequence. It is not exhaustive, rather it aims to show only the pieces | |
| where the system RAM is modified. See arch/arm/lib/crt0* to understand the | |
| complete execution sequence. | |
| Also note that the below sequence is not a hard and fast rule on how DRAM usage | |
| would be and an architecture and board specific analysis is required for the | |
| exact flow. | |
| SPL Flow | |
| ........ | |
| #. Pre-DRAM | |
| Prior to setting up of the DRAM, the stack, malloc is defined as below | |
| possibly sitting on a smaller readily available memory (SRAM etc.): | |
| .. image:: pics/spl_before_reloc.svg | |
| :alt: contents of ready RAM before relocation in SPL | |
| Please see CONFIG_SPL_EARLY_BSS if BSS initialization is needed prior | |
| to entering board_init_f(). | |
| #. DRAM Initialization | |
| This is typically triggered by board_init_f prior to relocating the stack | |
| and the GD (optionally) to the system RAM. DRAM drivers reside in | |
| drivers/ram/. Their probe/configuration can be done either via placing the | |
| logic in dram_init() or wherever deemed applicable within board_init_f. | |
| Post board_init_f, spl_relocate_stack_gd() is called to relocate the stack | |
| and the GD to the newly initialized DRAM. If CONFIG_SPL_SYS_MALLOC_SIMPLE | |
| is set it is also possible to use some amount of this DRAM stack as memory | |
| pool for malloc_simple. | |
| Both of which are an optional move at this point in the sequence. This is | |
| still an intermediate environment. | |
| #. Final Environment Set Up | |
| The final environment is setup and the system RAM now looks like this: | |
| .. image:: pics/spl_after_reloc.svg | |
| :alt: contents of DRAM after relocation in SPL | |
| Again stack and gd are an optional move and may still remain in the | |
| available RAM (SRAM, locked cache etc.) | |
| U-Boot Proper Flow | |
| .................. | |
| TODO: this section is still under progress | |
| #. DRAM Initialization | |
| This follows the same as in SPL flow. In board_init_f(), a part of memory | |
| is reserved at the end of RAM (see reserve_* functions in init_sequence_f) | |
| #. Code Relocation | |
| relocate_code() is called which relocates U-Boot code from the current | |
| location into the relocation destination in system RAM. Typically it is | |
| relocated to the upper portion of the memory. So DRAM now has: | |
| * stack | |
| * gd | |
| * code | |
| The code relocation happens to the upper portion of the memory after certain | |
| portion of memory is reserved. This is memory that is intended to not be | |
| "touched" by U-Boot. | |
| #. Final Environment Set Up | |
| At this stage we are completely running out of the system RAM with: | |
| * stack | |
| * gd | |
| * code | |
| * bss | |
| * initialized non-const data | |
| * initialized const data | |
| It is better to do a complete analysis to visualize the layers the system | |
| RAM is composed of at the end of this flow. This is entirely dependent on | |
| CPU/SoC architecture. | |
| Getting information about system RAM | |
| .................................... | |
| At boot: | |
| The prints given by announce_dram_init() and show_dram_config() come up in the | |
| boot banner like so:: | |
| DRAM: 2 GiB (total 32 GiB) | |
| U-Boot supports addressing upto 39-bit. To avoid trying to access higher | |
| addresses in systems with > 39-bit addresses, U-Boot caps itself (gd->ram_size) | |
| to the first bank. This is also inline with philosophy that U-Boot is a | |
| bootloader and not a full-fledged operating system. The first value represents | |
| this memory that is available for U-Boot while the "total" value represents the | |
| total system RAM available on the device. | |
| Getting the most basic information on how system RAM has been set up is by | |
| running `bdinfo` at U-Boot prompt:: | |
| => bdinfo | |
| boot_params = 0x0000000000000000 | |
| DRAM bank = 0x0000000000000000 | |
| -> start = 0x0000000080000000 | |
| -> size = 0x0000000080000000 | |
| DRAM bank = 0x0000000000000001 | |
| -> start = 0x0000000880000000 | |
| -> size = 0x0000000780000000 | |
| flashstart = 0x0000000000000000 | |
| flashsize = 0x0000000000000000 | |
| flashoffset = 0x0000000000000000 | |
| baudrate = 115200 bps | |
| relocaddr = 0x00000000ffec1000 | |
| reloc off = 0x000000007f6c1000 | |
| Build = 64-bit | |
| current eth = ethernet@46000000port@1 | |
| ethaddr = 3c:e0:64:62:4b:4e | |
| IP addr = <NULL> | |
| fdt_blob = 0x00000000fde7df60 | |
| lmb_dump_all: | |
| memory.count = 0x1 | |
| memory[0] [0x80000000-0xffffffff], 0x80000000 bytes flags: none | |
| reserved.count = 0x2 | |
| reserved[0] [0x9e800000-0xabffffff], 0x0d800000 bytes flags: no-map | |
| reserved[1] [0xfce79f50-0xffffffff], 0x031860b0 bytes flags: no-overwrite | |
| devicetree = separate | |
| serial addr = 0x0000000002880000 | |
| width = 0x0000000000000000 | |
| shift = 0x0000000000000002 | |
| offset = 0x0000000000000000 | |
| clock = 0x0000000002dc6c00 | |
| arch_number = 0x0000000000000000 | |
| TLB addr = 0x00000000ffff0000 | |
| irq_sp = 0x00000000fde7df50 | |
| sp start = 0x00000000fde7df50 | |
| Early malloc usage: 3288 / 8000 | |
| Here you are able to see the banks of DDR that have been set up in DRAM bank | |
| -> start and -> size as well as the reserved memories in lmb_dump_all. | |
| Testing Memory | |
| -------------- | |
| Please see doc/README.memory-test |