5

Please tell me, why my simple application cannot mmap a small size of memory?

And, why such a specific boundary - 257UL?

// #define MAP_SIZE 256UL or below - fail
// #define MAP_SIZE 257UL - ok

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <errno.h>
#include <signal.h>
#include <fcntl.h>
#include <ctype.h>
#include <termios.h>
#include <sys/types.h>
#include <sys/mman.h>

#define FATAL do { fprintf(stderr, "Error at line %d, file %s (%d) [%s]\n", \
  __LINE__, __FILE__, errno, strerror(errno)); exit(1); } while(0)

#define MAP_SIZE 4096UL
#define MAP_MASK (MAP_SIZE - 1)

int main(int argc, char **argv) {
    int fd;
    void *map_base, *virt_addr;
    unsigned long read_result, writeval;
    off_t target = strtoul("0x00002000", 0, 0);

    if((fd = open("/dev/mem", O_RDWR | O_SYNC)) == -1) FATAL;
    printf("/dev/mem opened.\n");
    fflush(stdout);

    map_base = mmap(0, MAP_SIZE, PROT_READ | PROT_WRITE, MAP_SHARED, fd, target & ~MAP_MASK);
    if(map_base == (void *) -1) FATAL;
    printf("Memory mapped at address %p.\n", map_base);
    fflush(stdout);
...
}
Jake Badlands
  • 1,016
  • 3
  • 23
  • 46
  • Error while trying to mmap: Invalid argument – Jake Badlands Oct 10 '12 at 08:59
  • 1
    @JakeBadlands: have you inspected the value of the last parameter of your call to `mmap`, `target & ~MAP_MASK`? Also, `MAP_ANONYMOUS` would be a cleaner way to map into memory instead of opening a file. – Blagovest Buyukliev Oct 10 '12 at 09:07
  • @BlagovestBuyukliev unfortunately, `MAP_ANONYMOUS` does not help. – Jake Badlands Oct 10 '12 at 09:27
  • 1
    Do you set MAP_SIZE? If so, your MAP_MASK is adjusted to it, and aligning `target & ~MAP_MASK` works weirdly: when MAP_SIZE is 256, the mask is 0x000000FF, which is not a page boundary (offset is not a multiple of the page size). Though I still don't understand why it works when MAP_SIZE is 257. – Dmytro Sirenko Oct 10 '12 at 10:05
  • 1
    @EarlGray , The mask is bitwise inverted, so the result used for the offset is 0x2000 (8192) for any MAP_SIZE < 8192 – nos Oct 10 '12 at 11:52

2 Answers2

4

Probably you just don't have the rights to write to /dev/mem. This is probably not what you want, mapping all the low end physical memory into your address space.

Have a look into shm_open to open memory segments or MAP_ANONYMOUS to map anonymously.

Edit:

Do a man mem to know what the /dev/mem device node is about:

Byte addresses in mem are interpreted as physical memory addresses. References to nonexistent locations cause errors to be returned.

If you want to map to a device node to have a memory segment you should use /dev/zero, but nowadays the tools I describe above should be sufficient.

Then don't, really don't, run such a code with root privileges unless you really know what you are doing. Writing into the physical memory and thus overwriting kernel and userspace data and programs can only lead to catastrophes.

Jens Gustedt
  • 76,821
  • 6
  • 102
  • 177
  • If that is the case, why I am able to mmap a slightly bigger size of memory? Also, I am running at root mode. – Jake Badlands Oct 10 '12 at 09:14
  • 1
    `/dev/mem` is simply not the right tool, it may have restrictions/protections for the low end of the address space whatever. You shouldn't really do that unless you know exactly what you are doing, that is if you are expert in the linux kernel. I'll do an edit to explain that more. – Jens Gustedt Oct 10 '12 at 09:57
  • Why root? I'm doing that on Xubuntu LiveCD, so if something goes wrong, I don't care - a simple restart will fix that. – Jake Badlands Oct 10 '12 at 11:04
4

mmap works in multiples of the page size on your system. If you're doing this on i386/amd64 or actually most modern CPUs, this will be 4096.

In the man page of mmap on my system it says: "offset must be a multiple of the page size as returned by sysconf(_SC_PAGE_SIZE).". On some systems for historical reasons the length argument may be not a multiple of page size, but mmap will round up to a full page in that case anyway.

Art
  • 19,807
  • 1
  • 34
  • 60
  • 1
    @nos Yup. I noticed that, so I answered the general question rather than the specific here. For the specific, it's hard to know since playing around with /dev/mem is not only operating system dependent, but also dependent on the particular machine you're running on and the other answer saying "don't touch /dev/mem" answered that adequately. – Art Oct 10 '12 at 11:52