mmap on /proc/pid/mem - c

Has anybody succeeded in mmap'ing a /proc/pid/mem file with Linux kernel 2.6? I am getting an ENODEV (No such device) error. My call looks like this:
char * map = mmap(NULL, PAGE_SIZE, PROT_READ, MAP_SHARED, mem_fd, offset);
And I have verified by looking at the /proc/pid/maps file while debugging that, when execution reaches this call, offset has the value of the top of the stack minus PAGE_SIZE. I have also verified with ptrace that mmap is setting errno to ENODEV.

See proc_mem_operations in /usr/src/linux/fs/proc/base.c: /proc/.../mem does not support mmap.

Related

mmap PCIe BAR and print content of addr is ffffffff

I tried to use mmap() in the linux user mode to map the resource2 file in sysfs to obtain the BAR of the pcie device. The code is shown below.
char *devname = "/sys/bus/pci/devices/0000:04:00.2/resource2";
res_fd = open(devname, O_RDWR);
if (res_fd < 0)
goto fail;
map_addr = mmap(NULL, pci->mem_resource[i].len,
PROT_READ | PROT_WRITE,
MAP_SHARED, res_fd, 0);
if (map_addr == MAP_FAILED)
goto fail;
printf ("%x\n", ((unsigned char*)map_addr)[0x100]);
Finally, the output of this code is ffffffff.
I am very sure that this is abnormal. I checked the datasheet of the device and its output should be a fixed constant, such as 0x37e3cf5.
Actually, I got ffffffff on ubuntu 18.04 kernel 4.19+, but the correct 0x37e3cf5 on ubuntu 18.04 kernel 5.4+.
I want to know what caused the difference of pcie's source file in sysfs. It has tortured me for a long time
Thank you!
I found the answer shortly after the question was posted, it may be caused by AMD’s Secure Memory Encryption function, so I turned off the sme function in the kernel parameters of gurb and everything was normal.

Not able to write in /dev/mem

The issue that I am experimenting is not related with open() or mmap() function, which are executed properly. I have disabled CONFIG_STRICT_DEVMEM in the kernel so I can read from /dev/mem without problems. Actually, I can do the following:
const char *path = "/dev/mem"
int fd = open(path, O_RDWR); /* read and write flags*/
p = mmap(0, SIZE, PROT_READ | PROT_WRITE, MAP_SHARED, fd, BASE_ADDR); /* read and write flags*/
And the code does not fail. Nonetheless, I am using this code to write in the PCI address space. So, basically the BASE_ADDR is 0xc000000, and the size is 256 MiB (0x10000000, all the PCI address space).
Said that, when I try to write on these positions (with a specific offset, BDF format), nothing is written; again the code does not fail, it just does not write anything.
In case my code was wrong, I tried BusyBox, with the following parameters:
[horro# ~]$ sudo busybox devmem 0xc00b0a8c w 0xffffffff
[horro# ~]$ sudo busybox devmem 0xc00b0a8c
0x00000000
So, basically it is not writing anything.
There is a CONFIG_STRICT_DEVMEM kernel config option. My understanding is that it must be set at compile-time as CONFIG_STRICT_DEVMEM=n. This is a security reasons.

copy_to_user fails to copy data to mmap user from kernel?

In the user space programm I am allocating some memory via mmap as the following function call:
void *memory;
int fd;
fd = open(filepath, O_RDWR);
if (fd < 0)
return errno;
memory = mmap(NULL, 4096, PROT_WRITE, MAP_SHARED, fd, 0);
if (memory == MAP_FAILED)
return -1;
//syscall() goes here
In the kernel space in my system call I am trying to copy data to the memory mapped region as follows:
copy_to_user(memory,src,4096);
EDIT: added error checking code to the post for clarification
The copy_to_user() call is repeatedly failing in this case, whereas if I would have done a memory = malloc() it was succeeding always.
Am I getting some permission flags wrong in this case for mmap ?
Does the open succeed? What about mmap? Is the target file big enough? Can you write to the file through the mapping in userspace?
Also, the repeated 4096 is a strong hit your code is wrong. Userspace should pass the expected size instead.

Linux userspace DMA access (for memory-memory copy)

My embedded ARM device has a 800x480 16 bit Linux framebuffer LCD which needs to be double-buffered manually.
At the moment I'm just using memcpy() to write the double buffer to the framebuffer which is awfully slow. A while(1){memcpy(lfb,dbuf)} loop maxes out the CPU at 100% and updates at approx 40 FPS.
The ARM device I'm using, and the Linux kernel does support DMA memory-memory copy, but I'm having trouble working out how I can access this in a userspace program.
It seems linux/dmaengine.h and dma_async_memcpy_buf_to_buf() is what I need to use, but it appears these are only available from within the kernel?
The proper way of what you are doing is not to copy memory at all, but just use your embedded display controller feature to read next frame from another mem buffer.
Ensure you SoC has/doesn't have this feature. I'm 80% sure it has.
this information, from: http://pandorawiki.org/Kernel_interface
may be helpful>
framebuffer interface
Framebuffers can be accessed Linux fbdev interface:
fbdev = open("/dev/fb0", O_RDWR);
buffer = mmap(0, 800*480*2, PROT_READ | PROT_WRITE, MAP_SHARED, fbdev, 0);
(this is basic example, no error checks)
the returned pointer can be used to draw on the screen.
Be sure to #include to get access to the FB device ioctl interface, and for access to ioctl itself.
double buffering
This can be achieved using FBIOPAN_DISPLAY ioctl system call. For this you need to mmap framebuffer of double size
buffer1 = mmap(0, 800*480*2 * 2, PROT_WRITE, MAP_SHARED, fbdev, 0);
buffer2 = (char *)mem + 800*480*2;
Then to display buffer2 you would call:
struct fb_var_screeninfo fbvar;
ioctl(fbdev, FBIOGET_VSCREENINFO, &fbvar);
fbvar.yoffset = 480;
ioctl(fbdev, FBIOPAN_DISPLAY, &fbvar);
going back to buffer1 would be repeating above with fbvar.yoffset = 0. Tripple or quad buffering can be implemented using the same technique.

What is the difference between MAP_SHARED and MAP_PRIVATE in the mmap function?

Playing around with mmap for the fun of it, I have the following code:
(.. snip ..)
fd = open("/home/me/straight_a.txt", O_RDONLY);
if (fd == -1) {
perror("open");
exit(1);
}
m = mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_FILE|MAP_PRIVATE, fd, 0);
if (m == MAP_FAILED) {
perror("mmap");
exit(1);
}
printf("m is %p\n", m);
printf("*m = %c\n", *m);
printf("*(m+1) = %c\n", *(m+1));
(.. snip ..)
This works as expected. But before I got to this, I tried...
m = mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_FILE|MAP_SHARED, fd, 0);
... and mmap errored out with:
mmap: Permission denied
In general, what's the difference between the two flags (man page isn't to generous on this subject)? What sort of permission (and where) am I missing?
EDIT
Like it usually happens.. partially figured it out.
Turns out open needed an O_RDWR flag.
So, am I correct to assume that:
MAP_PRIVATE - changes are made in memory only, not saved to disk?
MAP_SHARED - changes would be saved to disk...
... but I'm not saving anything to disk anywhere, I thought? Just operating on memory.
You opened the file in read-only mode. Then you attempted to mmap part of it in read/write mode with MAP_SHARED set. In this context, MAP_SHARED implies that if you write to the mmap'd region your changes will be committed back to the mapped file itself. You can't do this because you opened the file in read-only mode.
MAP_PRIVATE works because writes to the mmap'd region are not committed back to the original file. When you write to the region, the pages that were written to are copied to a different region of memory, possibly backed by swap space.
Writes to a MAP_SHARED segment are carried through to the underlying file. You opened the file with O_RDONLY, which conflicts with the PROT_WRITE flag, thereby preventing MAP_SHARED from being able to write back to the file.
MAP_PRIVATE does not carry writes back to the underlying file, so the fact that you opened the file O_RDONLY is not an issue.

Resources