I/O memory access and hardware page mappings
adam at os.inf.tu-dresden.de
Tue Jul 25 23:47:26 CEST 2017
On Mon Jul 24, 2017 at 16:55:37 +0200, Paul Boddie wrote:
> Having looked at the l4vbus_gpio functions and struggled with providing
> suitable devices, I decided to take the simpler approach and just ask for the
> I/O memory of the devices and access that directly. However, this didn't prove
> as straightforward as anticipated, either.
> The aim was to take the previously-mentioned device resources of the following
> form and to perform l4io_request_iomem (or l4io_request_resource_iomem) to get
> addresses of virtual regions corresponding to the different physical memory
> PORTA = Hw.Device(function()
> Property.hid = "jz4780-gpio-PORTA";
> Resource.regs = Res.mmio(0x10010000, 0x100100ff);
> PORTB = Hw.Device(function()
> Property.hid = "jz4780-gpio-PORTB";
> Resource.regs = Res.mmio(0x10010100, 0x100101ff);
> PORTF = Hw.Device(function()
> Property.hid = "jz4780-gpio-PORTF";
> Resource.regs = Res.mmio(0x10010500, 0x100105ff);
> It was indeed possible to obtain the resources involved with individual ports
> and also to obtain an address for each port region. However, accesses relative
> to these base addresses did not produce the expected results (LED output
> changes, switch input changes).
> (Looking at the virtual and physical regions in jdb suggested that the
> accesses were not being propagated, although I was also not successful in
> putting values into physical memory addresses and obtaining any of the
> expected results, either.)
> Now, I did wonder how such a small, 256-byte region mapping would actually
> work with my hardware. The JZ4780 does not support pages smaller than 4K when
> mapping memory, but I did notice that I do get an exception if trying to
> access beyond the end of the virtual region.
> (I found this out when considering that perhaps the virtual address might
> actually point to the base of the hardware page containing the region. So, I
> added a region offset to the base and tried to perform a memory access.
> Obviously, returning the hardware page address would be an unfortunate choice
> because it would oblige the API user to know about such things. Clearly, the
> API should return the address of the actual region, and maybe it does.)
> So, if this smaller-than-hardware page size is enforced, there must be a
> mechanism above the plain TLB mechanism that performs such enforcement. One
> interesting thing I noticed was that when requesting two different regions,
> the virtual addresses for the base of the regions were 4K apart, not 256 bytes
> apart. In any case, I was left wondering if any such mechanism might be
> preventing accesses from being correctly propagated.
> To simplify things a bit more, I then decided to just define the entire GPIO
> region in the device tree:
> GPIO = Hw.Device(function()
> Property.hid = "JZ4780 GPIO";
> Resource.regs = Res.mmio(0x10010000, 0x100105ff);
> Requesting the memory for this device succeeds as before, but then performing
> accesses relative to the returned virtual address (with port F at vaddr +
> 0x500, for instance) also succeeds and produces the desired result, unlike
> So, what is this mechanism that handles accesses to regions that do not
> correspond to hardware pages (either in size or alignment)? Is there some kind
> of address-based trapping that redirects accesses to some kind of privately-
> allocated page that is then mapped to the hardware page concerned? Is it
> possible that this mechanism does not work on MIPS or on my specific device?
There's no mechanism here that handles MMIO region sizes smaller than
page size. Rather, l4io_request_iomem and friends to not handle
addresses with offsets very well. Obviously I'll fix this.
For now, please just use page-aligned physical addresses (and size).
More information about the l4-hackers