I'm trying to parse some additional values from the device tree, and I'm running
into some issues. If I understand the logic in arch_setup_free_memory()
correctly [1], it reserves a region of RAM for the ELF, and makes the rest
available for use by the memory allocator / mmu subsystem.
If the bootloader happens to locate the DTB after the elf, it would not get
mapped in TTBR0 and we would no longer be able to address it via the global dtb
pointer. Further, it would risk getting overwritten by new mapped memory.
Add a check for this scenario, and reserve all memory up until the end of either
the dtb or elf, whichever address is higher.
On the qemu virt model, start of RAM is 0x40000000, and qemu places the dtb at
0x48000000, so unfortunately this wastes ~128MB of precious lowmem. I'm not very
familiar with the OSv mmu subsystem - does OSv have a way to reserve regions of
memory and guarantee that those pages won't be given away by a potential future
malloc?
As I was writing this, I just now realized that OSv parses the relevant DTB
values and stores them in known locations for later use. Is this the preferred
way to parse the DTB? If so, I can develop a patch assigning NULL to the global
DTB pointer when we switch to the runtime tables, along with a comment to
explain this.
[1]
https://github.com/cloudius-systems/osv/blob/master/arch/aarch64/arch-setup.cc#L75
arch/aarch64/arch-setup.cc | 10 +++++++++-
1 file changed, 9 insertions(+), 1 deletion(-)
diff --git a/arch/aarch64/arch-setup.cc b/arch/aarch64/arch-setup.cc
index 6aff9580..29b704f0 100644
--- a/arch/aarch64/arch-setup.cc
+++ b/arch/aarch64/arch-setup.cc
@@ -29,6 +29,12 @@
#include <alloca.h>
+extern "C" {
+#include "libfdt.h"
+}
+
+#define MAX(a,b) ((a)>(b) ? (a) : (b))
+
void setup_temporary_phys_map()
{
// duplicate 1:1 mapping into phys_mem
@@ -80,7 +86,9 @@ void arch_setup_free_memory()
extern size_t elf_size;
extern void *elf_start;
- mmu::phys addr = (mmu::phys)elf_start + elf_size;
+ mmu::phys elf_end_addr = (mmu::phys)elf_start + elf_size;
+ mmu::phys dtb_end_addr = (mmu::phys)dtb + fdt_totalsize(dtb);
+ mmu::phys addr = MAX(elf_end_addr, dtb_end_addr);
size_t reserved_size = addr - mmu::mem_addr;
mmu::free_initial_memory_range(addr, memory::phys_mem_size - reserved_size);
--
2.30.0