On 31/08/2026 13:01, Alperen Erkan wrote:

1.

    Representing the bounce threshold on i386/PAE

The first thing that caught my attention was that the following fields are defined as |unsigned long|:

|struct bus_dma_tag { unsigned long _bounce_thresh; }; unsigned long _dm_bounce_thresh;|

I don't see this. The patch clearly defines these with type 'unsigned long long'.

2.

    The |panic()| calls in |bus_dmamap_load_mbuf()| and
    |bus_dmamap_load_uio()|

Both functions call |panic()| when direct mapping fails:

|panic("bus_dmamap_load_mbuf bounce buffers"); |

and:

|panic("bus_dmamap_load_uio bounce buffers"); |

The comments state that Hurd does not currently use these interfaces. However, since the change is being added to the general rump DMA implementation, a driver using either path in the future could cause the entire process to crash simply by encountering a normal buffer above 4 GiB.

In the future is indeed the point. Developing "in the future" would show that work needs to be done in this area should the case you mention arise.

If bounce support for these paths is not going to be implemented yet, returning an appropriate error code may be safer than calling |panic()|. Have you confirmed that neither of these paths can be reached by any of the current Hurd drivers?

Possibly 'panic' is excessive but there are a number of cases in the rump dma code that already call panic for unsupported cases. I was being consistent with those. I have not checked whether rumpnet or rumpusbdisk use these interfaces but I've not heard of those failing on systems with 3.5G or more of RAM. Only a device that is limited to a 32 bit PCI addressing capability can be affected by this change.

As far as I can see, |bus_dmamap_load()|, |bus_dmamap_load_mbuf()|, and |bus_dmamap_load_uio()| have been considered, but no equivalent bounce-threshold check has been added to |bus_dmamap_load_raw()|.

If raw segments contain DMA addresses directly, a segment above the 32-bit limit may be able to bypass the new mechanism. Even if applying a bounce buffer to the raw-loading path is not possible, should the supplied segments not at least be checked against |_dm_bounce_thresh|, with an error returned when they exceed it?

I don't know but will check.

4.

    Allocating a bounce buffer for every map in advance

When a bounce threshold is enabled, |bus_dmamap_create()| immediately allocates a bounce buffer alongside the cookie:

|error = _bus_dma_alloc_bouncebuf(t, map, size, flags); |

This appears to mean that every map created with the relevant DMA tag allocates low-address memory, regardless of whether bouncing is actually required.

This is what the x86 arch code does.

This may cause unnecessary memory consumption, particularly for drivers that create a large number of DMA maps. It could also cause a buffer that would otherwise be mapped directly to fail during |bus_dmamap_create()| merely because an unused bounce buffer could not be allocated.

Theoretically, yes, but Hurd does not allocate large numbers of such maps.

5.

    Treating every mapping failure as a need to bounce

Within |bus_dmamap_load()|, if the first |_bus_dmamap_load_buffer()| call fails, the operation is retried through the bounce buffer without distinguishing the reason for the failure.

However, the first mapping attempt may fail not only because the DMA address exceeds the threshold, but also because the segment limit has been exceeded or because of another mapping constraint. Of course, this may be intentional, since a bounce buffer can also resolve some segment-fragmentation problems.

Nevertheless, it would be helpful to clarify whether bouncing is intended only for threshold violations or for every mapping failure. If only threshold violations are meant to trigger it, a distinct error code or an explicit “bounce required” result may make the behaviour clearer.

This is what the x86 arch code does. I'm not trying to improve on NetBSD; merely making what is available under x86 available under rump/x86.

6.

    Ensuring that the bounce buffer is allocated below the threshold

The bounce buffer is allocated through the following call:

|bus_dmamem_alloc(t, ...); |
bus_dmamem_alloc is implemented within Hurd by rumpcomp_pci_dmalloc() which only returns pages within the 32 bit physical address space.

7.

    Architectures other than x86

The |bus_dmamap_sync()| implementation ends with the following condition for non-x86 architectures:

|#else #error "bus_dmamap_sync unsupported" #endif |

If this file is also compiled as a general rump component on other architectures, the change may prevent every non-x86 build from compiling. This may be acceptable if the patch will be maintained solely for Hurd’s i386 and amd64 targets. However, if general portability is meant to be preserved, the previous |membar_sync()| behaviour could perhaps remain as the fallback for other architectures.

This is a Hurd specific patch. This patch will not be sent to NetBSD for inclusion. I'm very aware that it is not suitable for that. I will be contacting NetBSD people initially with a description of the problem and an outline of my solution. Code suggestions will be made if they wish based on their feedback.

Finally, I would be interested to know which scenarios you used to test the patch. In particular, if you tested it on an actual i386/PAE environment using physical addresses above 4 GiB, could you share the results? Tests covering |PREWRITE|, |POSTREAD|, partial offset/length synchronisation, and repeated load/unload cycles would also be useful.

I have tested that the code works on i386/PAE and verified that the bounce buffer code is triggered and that physical pages from beyond the 32 bit address space were supplied in the call to rump_psysread().

Mike.

Reply via email to