On Fri, Dec 29, 2023 at 05:36:09AM +0000, Simon Glass wrote: > Hi, > > On Sat, Dec 16, 2023 at 6:01 PM Simon Glass <s...@chromium.org> wrote: > > > > Hi, > > > > This records my thoughts after a discussion with Ilias & Heinrich re > > memory allocation in U-Boot. > > > > 1. malloc() > > > > malloc() is used for programmatic memory allocation. It allows memory > > to be freed. It is not designed for very large allocations (e.g. a > > 10MB kernel or 100MB ramdisk). > > > > 2. lmb > > > > lmb is used for large blocks of memory, such as those needed for a > > kernel or ramdisk. Allocation is only transitory, for the purposes of > > loading some images and booting. If the boot fails, then all lmb > > allocations go away. > > > > lmb is set up by getting all available memory and then removing what > > is used by U-Boot (code, data, malloc() space, etc.) > > > > lmb reservations have a few flags so that areas of memory can be > > provided with attributes > > > > There are some corner cases...e.g. loading a file does an lmb > > allocation but only for the purpose of avoiding a file being loaded > > over U-Boot code/data. The allocation is dropped immediately after the > > file is loaded. Within the bootm command, or when using standard boot, > > this would be fairly easy to solve. > > > > Linux has renamed lmb to memblock. We should consider doing the same. > > > > 3. EFI > > > > EFI has its own memory-allocation tables. > > > > Like lmb, EFI is able to deal with large allocations. But via a 'pool' > > function it can also do smaller allocations similar to malloc(), > > although each one uses at least 4KB at present. > > > > EFI allocations do not go away when a boot fails. > > > > With EFI it is possible to add allocations post facto, in which case > > they are added to the allocation table just as if the memory was > > allocated with EFI to begin with. > > > > The EFI allocations and the lmb allocations use the same memory, so in > > principle could conflict. > > > > EFI allocations are sometimes used to allocate internal U-Boot data as > > well, if needed by the EFI app. For example, while efi_image_parse() > > uses malloc(), efi_var_mem.c uses EFI allocations since the code runs > > in the app context and may need to access the memory after U-Boot has > > exited. Also efi_smbios.c uses allocate_pages() and then adds a new > > mapping as well. > > > > EFI memory has attributes, including what the memory is used for (to > > some degree of granularity). See enum efi_memory_type and struct > > efi_mem_desc. In the latter there are also attribute flags - whether > > memory is cacheable, etc. > > > > EFI also has the x86 idea of 'conventional' memory, meaning (I > > believe) that below 4GB that isn't reserved for the hardware/system. > > This is meaningless, or at least confusing, on ARM systems. > > > > 4. reservations > > > > It is perhaps worth mentioning a fourth method of memory management, > > where U-Boot reserves chunks of memory before relocation (in > > board_init_f.c), e.g. for the framebuffer, U-Boot code, the malloc() > > region, etc. > > > > > > Problems > > —------- > > > > There are no urgent problems, but here are some things that could be > > improved: > > > > 1. EFI should attach most of its data structures to driver model. This > > work has started, with the partition support, but more effort would > > help. This would make it easier to see which memory is related to > > devices and which is separate. > > > > 2. Some drivers do EFI reservations today, whether EFI is used for > > booting or not (e.g. rockchip video rk_vop_probe()). > > > > 3. U-Boot doesn't really map arch-specific memory attributes (e.g. > > armv8's struct mm_region) to EFI ones. > > > > 4. EFI duplicates some code from bootm, some of which relates to > > memory allocation (e.g. FDT fixup). > > > > 5. EFI code is used even if EFI is never used to boot > > > > 6. EFI allocations can result in the same memory being used as has > > already been allocated by lmb. Users may load files which overwrite > > memory allocated by EFI. > > 7. We need to support doing an allocation when a file is loaded (to > ensure files do not overlap), without making it too difficult to load > multiple files to the same place, if desired. > > > > > > > Lifetime > > -------- > > > > We have three different memory allocators with different purposes. Can > > we unify them a little? > > > > Within U-Boot: > > - malloc() space lives forever > > - lmb lives while setting out images for booting > > - EFI (mostly) lives while booting an EFI app > > > > In practice, EFI is set up early in U-Boot. Some of this is necessary, > > some not. EFI allocations stay around forever. This works OK since > > large allocations are normally not done in EFI, so memory isn't really > > consumed to any great degree by the boot process. > > > > What happens to EFI allocations if the app returns? They are still > > present, in case another app is run. This seems fine. > > > > API > > –-- > > Can we unify some APIs? > > > > It should be possible to use lmb for large EFI memory allocations, so > > long as they are only needed for booting. We effectively do this > > today, since EFI does not manage the arrangement of loaded images in > > memory. for the most part. > > > > It would not make sense to use EFI allocation to replace lmb and > > malloc(), of course. > > > > Could we use a common (lower-level) API for allocation, used by both > > lmb and EFI? They do have some similarities. However they have > > different lifetime constraints (EFI allocations are never dropped, > > unlikely lmb). > > > > ** Overall, it seems that the existence of memory allocation in > > boot-time services has created confusion. Memory allocation is > > muddled, with both U-Boot code and boot-time services calling the same > > memory allocator. This just has not been clearly thought out. > > > > > > Proposal > > —------- > > > > Here are some ideas: > > > > 1. For video, use the driver model API to locate the video regions, or > > block off the entire framebuffer memory, for all devices as a whole. > > Use efi_add_memory_map() > > > > 2. Add memory attributes to UCLASS_RAM and use them in EFI, mapping to > > the EFI_MEMORY_... attributes in struct efi_mem_desc. > > > > 3. Add all EFI reservations just before booting the app, as we do with > > devicetree fixup. With this model, malloc() and lmb are used for all > > allocation. Then efi_add_memory_map() is called for each region in > > turn just before booting. Memory attributes are dealt with above. The > > type (enum efi_memory_type) can be determined simply by the data > > structure stored in it, as is done today. For example, SMBIOS tables > > can use EFI_ACPI_RECLAIM_MEMORY. Very few types are used and EFI code > > understands the meaning of each. > > > > 4. Avoid setting up EFI memory at the start of U-Boot. Do it only when > > booting. This looks to require very little effort. > > > > 5. Avoid calling efi_allocate_pages() and efi_allocate_pool() outside > > boot-time services. This solves the problem 6. If memory is needed by > > an app, allocate it with malloc() and see 3. There are only two > > efi_allocate_pages() (smbios and efi_runtime). There are more calls of > > efi_allocate_pool(), but most of these seem easy to fix up. For > > example, efi_init_event_log() allocates a buffer, but this can be > > allocated in normal malloc() space or in a bloblist. > > > > 6. Don't worry too much about whether EFI will be used for booting. > > The cost is likely not that great: use bootstage to measure it as is > > done for driver model. Try to minmise the cost of its tables, > > particularly for execution time, but otherwise just rely on the > > ability to disable EFI_LOADER. > > 7. Add a flag to the 'load' command: > > -m <type> - make an lmb allocation for the file > <type> is the image type to use (kernel, ramdisk, flat_dt) > > any existing allocation for that type will be automatically freed > first. If <type> is "none" then no freeing is possible: any loaded > images just stack up in lmb. > > Add an 'lmb' (or memblock) command to allow listing and clearing allocations.
I would really not like to change the user interface and instead simply handle this with flags to whatever mark/allocation function is called. You can always overwrite things that are brought in to memory, you cannot overwrite U-Boot or our internals. Optionally noting that some previous load to memory has been at least partially overwritten could be helpful, if it's not too much extra logic. -- Tom
signature.asc
Description: PGP signature