I/O memory access and hardware page mappings

Paul Boddie paul at boddie.org.uk
Mon Jul 24 16:55:37 CEST 2017


Hello again,

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 
regions.

    PORTA = Hw.Device(function()
      Property.hid = "jz4780-gpio-PORTA";
      Resource.regs = Res.mmio(0x10010000, 0x100100ff);
      ...
    end);

    PORTB = Hw.Device(function()
      Property.hid = "jz4780-gpio-PORTB";
      Resource.regs = Res.mmio(0x10010100, 0x100101ff);
      ...
    end);

    ...

    PORTF = Hw.Device(function()
      Property.hid = "jz4780-gpio-PORTF";
      Resource.regs = Res.mmio(0x10010500, 0x100105ff);
      ...
    end);

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);
  end);

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 
before.

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?

I apologise if I should be answering my own questions by looking at the code 
or particular documentation resources.

Paul




More information about the l4-hackers mailing list