If you are working with direct hardware memory mapping on the Raspberry Pi 5 via /dev/gpiomem0, you might encounter a deeply counter-intuitive behavior: calling mmap() with a requested size of 0x2c001 bytes succeeds, but reducing that size by just 1 byte to 0x2c000 causes mmap() to fail and return MAP_FAILED (0xffffffffffffffff).

The Short Answer

This issue occurs due to the interaction between kernel memory page rounding and device driver size validation:

  • The Raspberry Pi 5 Linux kernel uses a 16 KB (16,384 bytes / 0x4000) page size.
  • When you pass 0x2c001 to mmap(), the kernel automatically rounds the allocation size up to the next page boundary: 0x30000 (12 pages).
  • When you pass 0x2c000, the value is already page-aligned (11 pages exact), so the kernel does not round it up.
  • The /dev/gpiomem0 driver requires a minimum mapping length that spans more than 11 pages (e.g., 12 pages / 0x30000 bytes) to cover all required peripheral registers. Because 0x2c000 falls short of the driver's required length, the driver rejects the call with -EINVAL.

Under the Hood: Page Granularity on the Raspberry Pi 5

Memory mapping operates on page granularity. While traditional 32-bit Raspberry Pi boards and standard x86_64 systems use 4 KB pages (0x1000 bytes), the 64-bit OS kernel shipped with the Raspberry Pi 5 (running the BCM2712 / RP1 architecture) is configured with 16 KB pages (0x4000) for improved memory controller throughput.

Here is how the kernel handles your two requested sizes:

Case 1: mapsize = 0x2c001 (180,225 bytes)

The kernel calculates page boundaries as follows: