All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH 0/2] hw/arm/raspi4b: fix guest RAM capped at ~1 GiB regardless of machine size
@ 2026-07-26 14:41 Marcelo Manzo
  2026-07-26 14:41 ` [PATCH 1/2] hw/arm/raspi4b: fix guest never seeing more than ~1 GiB of RAM Marcelo Manzo
  2026-07-26 14:41 ` [PATCH 2/2] tests/functional/aarch64: add raspi4b full-RAM regression test Marcelo Manzo
  0 siblings, 2 replies; 3+ messages in thread
From: Marcelo Manzo @ 2026-07-26 14:41 UTC (permalink / raw)
  To: qemu-devel, qemu-arm
  Cc: Peter Maydell, Philippe Mathieu-Daudé, Marcelo Manzo

While working on unrelated raspi4b issues, I noticed the guest never
seemed to have as much RAM as I'd given it and tracked it down to
hw/arm/raspi4b.c's raspi4_modify_dtb(): it decides whether to add a
second memory node above the 1 GiB peripheral hole by checking
info->ram_size, but that field is the boot loader's RAM budget for
where it's allowed to place the kernel/initrd/dtb image, itself always
capped to at most UPPER_RAM_BASE - vcram_size by
raspi_base_machine_init(). Since that capped value can never exceed
UPPER_RAM_BASE by construction, the condition was never true for any
raspi4b configuration -- the second node was never added, and the
guest never saw more than ~1 GiB of RAM regardless of the machine's
nominal size. board_ram_size(info->board_id), computed one line above
in the same function, is the value that was actually needed.

Patch 1 fixes it (one line); patch 2 adds a regression test.

Confirmed via direct measurement inside the guest ("free -h" /
/proc/meminfo) on raspi4b's default 2 GiB configuration:

    before: MemTotal:  943524 kB (~921 MiB)
    after:  MemTotal: 1905824 kB (~1861 MiB)

Also verified against two real, unmodified Raspberry Pi OS releases
(Debian 11/Bullseye and Debian 13/Trixie): both now report ~1.8 GiB of
usable RAM instead of ~900 MiB, with clean boots, working SSH, and no
kernel errors on either.

I also looked into extending this to raspi4b's real 4 GiB and 8 GiB
hardware variants (real boards exist in 1/2/4/8 GiB configurations),
since board_ram_size()'s encoding already supports arbitrary sizes and
this same bug meant the necessary split-memory-node path had never
actually been exercised at any size, ever. 2 GiB now works cleanly
with this fix (tested above); 4 GiB hits a real kernel panic
(`kernel BUG at arch/arm64/mm/mmu.c:192!` in early page-table setup,
addresses landing in the BCM2711 peripheral region around 0xfc000000)
that looks like it needs the "high peripheral alias" real BCM2711
firmware sets up for boards with enough RAM to otherwise collide with
that region -- out of scope for this series, so I'm leaving 4/8 GiB
support for later and keeping this fix minimal.

checkpatch.pl is clean (0 errors, 0 warnings) on both patches, and the
series builds standalone from a clean worktree
(--target-list=aarch64-softmmu). All 6 tests in
tests/functional/aarch64/test_raspi4.py pass, including the 5
pre-existing ones (no regression) and the new one added here.

Marcelo Manzo (2):
  hw/arm/raspi4b: fix guest never seeing more than ~1 GiB of RAM
  tests/functional/aarch64: add raspi4b full-RAM regression test

 hw/arm/raspi4b.c                        | 14 ++++++-
 tests/functional/aarch64/test_raspi4.py | 51 +++++++++++++++++++++++++
 2 files changed, 64 insertions(+), 1 deletion(-)

-- 
2.47.1



^ permalink raw reply	[flat|nested] 3+ messages in thread

* [PATCH 1/2] hw/arm/raspi4b: fix guest never seeing more than ~1 GiB of RAM
  2026-07-26 14:41 [PATCH 0/2] hw/arm/raspi4b: fix guest RAM capped at ~1 GiB regardless of machine size Marcelo Manzo
@ 2026-07-26 14:41 ` Marcelo Manzo
  2026-07-26 14:41 ` [PATCH 2/2] tests/functional/aarch64: add raspi4b full-RAM regression test Marcelo Manzo
  1 sibling, 0 replies; 3+ messages in thread
From: Marcelo Manzo @ 2026-07-26 14:41 UTC (permalink / raw)
  To: qemu-devel, qemu-arm
  Cc: Peter Maydell, Philippe Mathieu-Daudé, Marcelo Manzo

raspi4_modify_dtb() decides whether to add a second memory node above
the 1 GiB peripheral hole by checking info->ram_size -- but that field
is the boot loader's RAM budget for loading the kernel/initrd/dtb
image, itself always capped to at most UPPER_RAM_BASE - vcram_size by
raspi_base_machine_init(). Since that capped value can never exceed
UPPER_RAM_BASE by construction, the condition was never true for any
raspi4b configuration, and the second node was never added: the guest
never saw more than ~1 GiB of its nominal RAM, regardless of the
machine's actual size.

board_ram_size(info->board_id), computed one line above in the same
function, is the value that was actually needed -- the board's real
total RAM, not the boot loader's own budget for where it's allowed to
place the kernel image.

Confirmed via direct measurement inside the guest ("free -h" /
/proc/meminfo) on raspi4b's default 2 GiB configuration, before and
after:

    before: MemTotal:  943524 kB (~921 MiB)
    after:  MemTotal: 1905824 kB (~1861 MiB)

Also verified against two real, unmodified Raspberry Pi OS releases
(Debian 11/Bullseye and Debian 13/Trixie): both now report ~1.8 GiB of
usable RAM instead of ~900 MiB, with clean boots, working SSH, and no
kernel errors on either.

Signed-off-by: Marcelo Manzo <marcelomanzo@gmail.com>
---
 hw/arm/raspi4b.c | 14 +++++++++++++-
 1 file changed, 13 insertions(+), 1 deletion(-)

diff --git a/hw/arm/raspi4b.c b/hw/arm/raspi4b.c
index b92840e1b6..ca246ebb35 100644
--- a/hw/arm/raspi4b.c
+++ b/hw/arm/raspi4b.c
@@ -64,7 +64,19 @@ static void raspi4_modify_dtb(const struct arm_boot_info *info, void *fdt)
 
     ram_size = board_ram_size(info->board_id);
 
-    if (info->ram_size > UPPER_RAM_BASE) {
+    /*
+     * Bug: this used to compare info->ram_size (the boot-loader's RAM
+     * budget for loading the kernel/initrd/dtb, itself capped to at most
+     * UPPER_RAM_BASE - vcram_size by raspi_base_machine_init()) rather
+     * than the board's actual total RAM computed just above. Since that
+     * capped value can never exceed UPPER_RAM_BASE by construction, this
+     * condition was never true for any raspi4b configuration -- the
+     * second memory node was never added, and the guest never saw more
+     * than ~1 GiB regardless of the machine's nominal RAM size. Confirmed
+     * via direct measurement: default -m 2G returns ~916 MiB from
+     * "free -h" inside the guest, not 2 GiB.
+     */
+    if (ram_size > UPPER_RAM_BASE) {
         raspi_add_memory_node(fdt, UPPER_RAM_BASE, ram_size - UPPER_RAM_BASE);
     }
 }
-- 
2.47.1



^ permalink raw reply related	[flat|nested] 3+ messages in thread

* [PATCH 2/2] tests/functional/aarch64: add raspi4b full-RAM regression test
  2026-07-26 14:41 [PATCH 0/2] hw/arm/raspi4b: fix guest RAM capped at ~1 GiB regardless of machine size Marcelo Manzo
  2026-07-26 14:41 ` [PATCH 1/2] hw/arm/raspi4b: fix guest never seeing more than ~1 GiB of RAM Marcelo Manzo
@ 2026-07-26 14:41 ` Marcelo Manzo
  1 sibling, 0 replies; 3+ messages in thread
From: Marcelo Manzo @ 2026-07-26 14:41 UTC (permalink / raw)
  To: qemu-devel, qemu-arm
  Cc: Peter Maydell, Philippe Mathieu-Daudé, Marcelo Manzo

Guards against the bug fixed in the previous commit: boots raspi4b's
default 2 GiB configuration and checks that the guest actually sees
close to that (>1.9M kB), not the ~921 MiB the bug left it capped at.
Deliberately checks a threshold rather than the exact byte count of
either figure, since the precise number depends on how this specific
pinned kernel accounts for its own early reservations; the threshold
is comfortably between the two (943524 kB broken, 1905824 kB fixed,
confirmed by hand against this exact kernel/initrd).

Signed-off-by: Marcelo Manzo <marcelomanzo@gmail.com>
---
 tests/functional/aarch64/test_raspi4.py | 51 +++++++++++++++++++++++++
 1 file changed, 51 insertions(+)

diff --git a/tests/functional/aarch64/test_raspi4.py b/tests/functional/aarch64/test_raspi4.py
index 35ba6c24f7..55903e93d3 100755
--- a/tests/functional/aarch64/test_raspi4.py
+++ b/tests/functional/aarch64/test_raspi4.py
@@ -154,6 +154,57 @@ def test_arm_raspi4_rng_thermal(self):
         exec_command_and_wait_for_pattern(self, 'halt', 'reboot: System halted')
 
 
+    def test_arm_raspi4_full_ram(self):
+        kernel_path = self.archive_extract(self.ASSET_KERNEL_20190215,
+                                           member='boot/kernel8.img')
+        dtb_path = self.archive_extract(self.ASSET_KERNEL_20190215,
+                                        member='boot/bcm2711-rpi-4-b.dtb')
+        initrd_path = self.uncompress(self.ASSET_INITRD)
+
+        self.set_machine('raspi4b')
+        self.vm.set_console()
+        kernel_command_line = (self.KERNEL_COMMON_COMMAND_LINE +
+                               'earlycon=pl011,mmio32,0xfe201000 ' +
+                               'console=ttyAMA0,115200 ' +
+                               'panic=-1 noreboot ' +
+                               'dwc_otg.fiq_fsm_enable=0')
+        self.vm.add_args('-kernel', kernel_path,
+                         '-dtb', dtb_path,
+                         '-initrd', initrd_path,
+                         '-append', kernel_command_line,
+                         '-no-reboot')
+        self.vm.launch()
+        self.wait_for_console_pattern('Boot successful.')
+
+        # raspi4b's default machine RAM is 2 GiB, but raspi4_modify_dtb()
+        # used to compare the wrong field when deciding whether to add a
+        # second memory node above the 1 GiB peripheral hole (it checked
+        # the boot-loader's kernel/initrd-loading RAM budget, which is
+        # itself always capped to at most 1 GiB, rather than the board's
+        # actual total RAM) -- so that second node was never added for any
+        # raspi4b configuration, and the guest never saw more than ~1 GiB
+        # regardless of the machine's nominal RAM size. With the bug,
+        # MemTotal here is 943524 kB; fixed, it is 1905824 kB. Guard
+        # against a regression back to the ~1 GiB figure without hardcoding
+        # the exact byte count of either, which depends on how this
+        # specific pinned kernel accounts for its own reservations.
+        mem_total_kb = None
+        cmd_output = exec_command_and_wait_for_pattern(
+            self, 'cat /proc/meminfo', 'MemAvailable')
+        for line in cmd_output.decode('ascii', errors='replace').splitlines():
+            if line.startswith('MemTotal:'):
+                mem_total_kb = int(line.split()[1])
+                break
+        self.assertIsNotNone(mem_total_kb, 'MemTotal line not found')
+        self.assertGreater(mem_total_kb, 1900000,
+                           'guest RAM (%d kB) is far below the ~1.9 GiB '
+                           'expected for a 2 GiB raspi4b -- the second '
+                           'memory node above the 1 GiB peripheral hole '
+                           'is probably not being added' % mem_total_kb)
+
+        exec_command_and_wait_for_pattern(self, 'halt', 'reboot: System halted')
+
+
     def test_arm_raspi4_pcie(self):
         kernel_path = self.archive_extract(self.ASSET_KERNEL_20190215,
                                            member='boot/kernel8.img')
-- 
2.47.1



^ permalink raw reply related	[flat|nested] 3+ messages in thread

end of thread, other threads:[~2026-07-26 14:41 UTC | newest]

Thread overview: 3+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-07-26 14:41 [PATCH 0/2] hw/arm/raspi4b: fix guest RAM capped at ~1 GiB regardless of machine size Marcelo Manzo
2026-07-26 14:41 ` [PATCH 1/2] hw/arm/raspi4b: fix guest never seeing more than ~1 GiB of RAM Marcelo Manzo
2026-07-26 14:41 ` [PATCH 2/2] tests/functional/aarch64: add raspi4b full-RAM regression test Marcelo Manzo

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.