I am having trouble using a Linux UIO device from Java. The idea behind this device is that you have a peripheral with a set of registers that are memory mapped. In order to access these registers for reading and writing, the kernel module exposes a device file (e.g. /dev/ui0) which can be mmapped and the pointer used to interact with the registers. The following code in C++ demonstrates the behavior:
#include <sys/mman.h>
#include <sys/types.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/stat.h>
#include <assert.h>
#include <cstdio>
int main() {
size_t filesize = 256;
//Open file
int fd = open("/dev/uio0", O_RDWR);
assert(fd != -1);
//Execute mmap
void* mmappedData = mmap(NULL, filesize, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
assert(mmappedData != MAP_FAILED);
//Write the mmapped data to stdout (= FD #1)
volatile int* regs = (int*) mmappedData;
for(int i =0; i < 7; i++) printf("REG[%d]=0x%08x\n", i, regs[i]);
//Cleanup
int rc = munmap(mmappedData, filesize);
assert(rc == 0);
close(fd);
return 0;
}
The output of the code above is:
REG[0]=0x00000001
REG[1]=0x00000001
REG[2]=0x00000004
REG[3]=0x00000024
REG[4]=0xa0109146
REG[5]=0x00000024
REG[6]=0x000000b9
Which is correct. However, I am attempting to achieve the same with the following Java code:
public class RegisterFile {
private final RandomAccessFile mRegisterSetFile;
private final MappedByteBuffer mByteBuffer;
public RegisterFile(String deviceName) throws IOException {
LOGGER.log(Level.INFO, "Mapping device: {0}", deviceName);
mRegisterSetFile = new RandomAccessFile(deviceName, "rws");
LOGGER.log(Level.INFO, "File length is: {0}", mRegisterSetFile.length());
mByteBuffer = mRegisterSetFile.getChannel().map(FileChannel.MapMode.READ_WRITE, 0, 256);
dump();
}
public final void dump() throws IOException {
StringBuilder builder = new StringBuilder("\n");
for (Address address : Address.values()) {
builder.append(String.format("REGFILE[%02d] = 0x%08x\n", address.get(), mByteBuffer.getInt(address.get())));
}
LOGGER.log(Level.INFO, "{0}", builder.toString());
}
}
However the result is:
[junit] Jan 13, 2018 3:50:26 PM org.apache.hadoop.io.compress.gzipFpga.RegisterFile <init>
[junit] INFO: Mapping device: /dev/uio0
[junit] Jan 13, 2018 3:50:26 PM org.apache.hadoop.io.compress.gzipFpga.RegisterFile <init>
[junit] INFO: File length is: 0
[junit] Jan 13, 2018 3:50:26 PM org.apache.hadoop.io.compress.gzipFpga.GzipFpgaCompressor gzipCoreAvailable
[junit] SEVERE: Unable to read from GZIP core devices.
[junit] java.io.IOException: Invalid argument
[junit] at sun.nio.ch.FileDispatcherImpl.truncate0(Native Method)
[junit] at sun.nio.ch.FileDispatcherImpl.truncate(FileDispatcherImpl.java:80)
[junit] at sun.nio.ch.FileChannelImpl.map(FileChannelImpl.java:906)
[junit] at org.apache.hadoop.io.compress.gzipFpga.RegisterFile.<init>(RegisterFile.java:85)
I believe the reason is that File.length() returns 0, because this is not a real file. Is there a way to force the mapping of the file?
User contributions licensed under CC BY-SA 3.0