How to mmap() to correct address - c

I am trying to write an integer (1114129) from my HPS on Cyclone V Altera FPGA from a PUTTY window to a 32bit PIO on the FPGA side via lightweight axis interface. I am using mmap() and cannot get it to map to the address i want it to which is 0xff206000, instead its mapping to the address 0xb6f31000. My code and result is shown below.
#include <sys/stat.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <sys/mman.h>
#include <sys/time.h>
#include <math.h>
#define MAPPED_SIZE 4
#define DDR_RAM_PHYS 0xff206000
#define PAGESIZE 0x1000
//1114129
int main(void)
{
int _fdmem;
void *map;
int a;
int c = 1114129;
const char memDevice[] = "/dev/mem";
_fdmem = open( memDevice, O_RDWR | O_SYNC );
if (_fdmem < 0){
printf("Failed to open the /dev/mem !\n");
return 0;
}
else{
printf("open /dev/mem successfully !\n");
}
a = sysconf(_SC_PAGESIZE);
printf("page %d", a);
/* mmap() the opened /dev/mem */
map = mmap(0, MAPPED_SIZE, PROT_READ|PROT_WRITE, MAP_SHARED, _fdmem, DDR_RAM_PHYS & -PAGESIZE);
if (map == MAP_FAILED) { perror("npheap_alloc()"); exit(1); }
int volatile * const p = (int *) (map + (0xff206000 % PAGESIZE));
*p = c;
printf("value %p", map);
printf("\nThe memory address of variable var = ptr = %p\n", p);
printf("\nIndirect access, variable var value = *ptr = %d", *p);
/* unmap the area & error checking */
if (munmap(map,MAPPED_SIZE)==-1){
perror("Error un-mmapping the file");
}
/* close the character device */
close(_fdmem);
}
open /dev/mem successfully !
page 4096value 0xb6f31000
The memory address of variable var = ptr = 0xb6f31000
Indirect access, variable var value = *ptr = 1114129#
Thanks in Advance

I think you're confusing the physical address (0xff206000) with the virtual address (0xb6f31000). You don't care what the virtual address is, you just what the pages at the physical address 0xff206000 to be mapped to any virtual address you can use.

The offset argument to mmap is a byte offset into the file. The pointer that mmap returns is a pointer to that location in the file, which in your case is a pointer to the exact address you want to write the value to.
So when you write the value, you write it to the exact location that map is pointing to:
int volatile * const map = (int volatile * const) mmap(...);
*map = value;

Related

Is there a maximum number of continuous pages per process in Linux? If so, how to set it to unlimited?

The following code will generate errno 12 cannot allocate memory
#include <sys/mman.h>
#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <memory.h>
#include <errno.h>
int main()
{
char* p;
for (size_t i = 0; i < 0x10000; i++)
{
char* addr = (char*)0xAAA00000000uL - i * 0x2000;
p = mmap(addr, 0x1000,
PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
if (p != addr) {
printf("%lu %d\n", i, errno);
getchar();
return 1;
}
memset(p, 'A' + (i % 26), 0x1000);
}
return 0;
}
The output is 65510 12 on my machine.
However, if we change size of each page from 0x1000 to 0x2000, the allocation will be successful, even if it is using more memory.
The only difference I think is the number of continuous pages, is there a limitation on this? If so, how to set it to unlimited?
It seems that setting /proc/sys/vm/max_map_count to a larger number solves the problem.
Reference: How much memory could vm use

How 8 bit memory access behaves when we replace replace the /dev/mem mapping with a normal memory allocation

So, I was observing how execution time behaves for various bit word, below is example of a program that read 8 bits word. I wanted to check how it behaves when we replace the /dev/mem mapping with a 'normal' memory allocation (i.e by malloc/calloc). But my code started giving segmentation fault (Core dump). Any help?
#include <fcntl.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/mman.h>
#include <sys/stat.h>
#include <unistd.h>
static uint32_t map_size = 0x08000000;
static uint32_t map_base = 0x18000000;
static uint32_t map_addr = 0x00000000;
static uint64_t cycle_count = 0x1000000;
static char *dev_mem = "/dev/mem";
int main(int argc, char **argv) {
int fd;
uint8_t *buf;
if ((fd = open(dev_mem, O_RDWR | O_SYNC)) == -1) {
printf("can't open /dev/mem .\n");
exit(EXIT_FAILURE);
}
buf = (uint8_t *) malloc(sizeof(uint8_t));
if (buf == 0) {
printf("Can't be mapped. \n");
exit(EXIT_FAILURE);
} else
map_addr = (long unsigned) buf;
uint8_t sum = 0;
while (cycle_count-- > 0)
sum += *buf++;
printf("%u\n", sum);
close(fd);
exit(EXIT_SUCCESS);
return 0;
}
I am new to this, so sorry if the errors are silly.
Take a look at this:
sum += *buf++;
You are adding the value that buf points to into sum and then incrementing buf. So you are actually incrementing the address, not the value.
Just adding a parenthesis should fix the problem:
sum += (*buf)++;
You should read more about the postfix increment operator and operator precedence.

Getting empty output when reading from file using "mmap"

I have a problem considering the usage of mmap. I am trying to map a pci device to a virtual address and read its content. In the future I am planning to write values to it as well.
The problem is that I (seemingly) successfully mapped the device to virtual memory space. However when I read the content of that virtual address all values are zero, despite the file not being empty.
Here is my code:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/mman.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <errno.h>
#include "../include/types.h"
#include "../include/pci.h"
#define PRINT_ERROR \
do { \
fprintf(stderr, "Error at line %d, file %s (%d) [%s]\n", \
__LINE__, __FILE__, errno, strerror(errno)); exit(1);\
} while(0)
#define MAP_SIZE 4069
#define MAP_MASK (MAP_SIZE - 1)
int main(int argc, char *argv[])
{
int pci_dev;
int *mmap_base;
int *content;
char file[] = {"/sys/bus/pci/devices/0000:04:00.0/resource"};
int i;
printf("File to be read from: %s\n", file);
pci_dev = open(file, O_RDONLY);
if (pci_dev < 0)
{
PRINT_ERROR;
}
mmap_base = mmap(NULL, MAP_SIZE, PROT_READ, MAP_PRIVATE | MAP_ANON, pci_dev, 0);
if (mmap_base == (void *)-1 || mmap_base == NULL)
{
PRINT_ERROR;
}
printf("Mapped on address %p of size %d Byte\n", mmap_base, (int)MAP_SIZE);
content = (int *)mmap_base;
for(i = 0; i < 1024; i++)
{
printf("%x", content[i]);
}
return 0;
}
Here's the content of the first line from the file "/sys/bus/pci/devices/0000:04:00.0/resource" that I am trying to access:
0x00000000cd000000 0x00000000cd07ffff 0x0000000000040200
However the output I get is:
File to be read from: /sys/bus/pci/devices/0000:04:00.0/resource
Mapped on address 0xb7705000 of size 4096 Byte
0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000...
Am I doing something wrong? Every help is appreciated!
Actually you've got 2 mistakes:
Don't use MAP_ANON when you create a map for a real file on the file system, it's meant for IPC and requiring extra memory from OS e.g. while malloc().
When you remove the flag, the mmap() will likely return ENODEV, because linux sysfs doesn't support mmaping; So you have to use read()'s here.

How to transfer FILE structure using Shared memory(POSIX SKIN)

I am using Shared memory (POSIX), to share a FILE pointer(FILE * rt_file), but it's not getting file pointer at client end. Any suggestions please.
/*
* shm_msgserver.c
*
* Illustrates memory mapping and persistency, with POSIX objects.
* This process produces a message leaving it in a shared segment.
* The segment is mapped in a persistent object meant to be subsequently
* open by a shared memory "client".
*
*
* Created by Mij <mij#bitchx.it> on 27/08/05.
* Original source file available at http://mij.oltrelinux.com/devel/unixprg/
*
*/
#include <stdio.h>
/* shm_* stuff, and mmap() */
#include <sys/mman.h>
#include <sys/types.h>
/* exit() etc */
#include <unistd.h>
#include <fcntl.h>
#include <sys/stat.h>
/* for random() stuff */
#include <stdlib.h>
#include <time.h>
/* Posix IPC object name [system dependant] - see
http://mij.oltrelinux.com/devel/unixprg/index2.html#ipc__posix_objects */
#define SHMOBJ_PATH "/foo1423"
/* maximum length of the content of the message */
#define MAX_MSG_LENGTH 50
/* how many types of messages we recognize (fantasy) */
#define TYPES 8
/* message structure for messages in the shared segment */
struct msg_s {
int type;
char content[MAX_MSG_LENGTH];
FILE *pt;
};
int main(int argc, char *argv[]) {
int shmfd;
int shared_seg_size = (1 * sizeof(struct msg_s)); /* want shared segment capable of storing 1 message */
struct msg_s *shared_msg; /* the shared segment, and head of the messages list */
FILE *rt_file;
rt_file = fopen ("res","a+");
printf("rt_file : %s\n",rt_file);
/* creating the shared memory object -- shm_open() */
shmfd = shm_open(SHMOBJ_PATH, O_CREAT | O_EXCL | O_RDWR, S_IRWXU | S_IRWXG);
if (shmfd < 0) {
perror("In shm_open()");
exit(1);
}
fprintf(stderr, "Created shared memory object %s\n", SHMOBJ_PATH);
/* adjusting mapped file size (make room for the whole segment to map) -- ftruncate() */
ftruncate(shmfd, shared_seg_size);
/* requesting the shared segment -- mmap() */
shared_msg = (struct msg_s *)mmap(NULL, shared_seg_size, PROT_READ | PROT_WRITE, MAP_SHARED, shmfd, 0);
if (shared_msg == NULL) {
perror("In mmap()");
exit(1);
}
fprintf(stderr, "Shared memory segment allocated correctly (%d bytes).\n", shared_seg_size);
srandom(time(NULL));
/* producing a message on the shared segment */
shared_msg->type = random() % TYPES;
snprintf(shared_msg->content, MAX_MSG_LENGTH, "My message, type %d, num %ld", shared_msg->type, random());
shared_msg->pt = rt_file;
/* [uncomment if you wish] requesting the removal of the shm object -- shm_unlink() */
/*
if (shm_unlink(SHMOBJ_PATH) != 0) {
perror("In shm_unlink()");
exit(1);
}
*/
return 0;
}
Client Code
/*
* shm_msgclient.c
* http://mij.oltrelinux.com/devel/unixprg/#ipc__posix_shm
* Illustrates memory mapping and persistency, with POSIX objects.
* This process reads and displays a message left it in "memory segment
* image", a file been mapped from a memory segment.
*
*
* Created by Mij <mij#bitchx.it> on 27/08/05.
* Original source file available at http://mij.oltrelinux.com/devel/unixprg/
*
*/
#include <stdio.h>
/* exit() etc */
#include <unistd.h>
/* shm_* stuff, and mmap() */
#include <sys/mman.h>
#include <sys/types.h>
#include <fcntl.h>
#include <sys/stat.h>
/* for random() stuff */
#include <stdlib.h>
#include <time.h>
/* Posix IPC object name [system dependant] - see
http://mij.oltrelinux.com/devel/unixprg/index2.html#ipc__posix_objects */
#define SHMOBJ_PATH "/foo1423"
/* maximum length of the content of the message */
#define MAX_MSG_LENGTH 50
/* how many types of messages we recognize (fantasy) */
#define TYPES 8
/* message structure for messages in the shared segment */
struct msg_s {
int type;
char content[MAX_MSG_LENGTH];
FILE *pt;
};
int main(int argc, char *argv[]) {
int shmfd;
int shared_seg_size = (1 * sizeof(struct msg_s)); /* want shared segment capable of storing 1 message */
struct msg_s *shared_msg; /* the shared segment, and head of the messages list */
FILE *rt_file;
/* creating the shared memory object -- shm_open() */
shmfd = shm_open(SHMOBJ_PATH, O_RDWR, S_IRWXU | S_IRWXG);
if (shmfd < 0) {
perror("In shm_open()");
exit(1);
}
printf("Created shared memory object %s\n", SHMOBJ_PATH);
/* requesting the shared segment -- mmap() */
shared_msg = (struct msg_s *)mmap(NULL, shared_seg_size, PROT_READ | PROT_WRITE, MAP_SHARED, shmfd, 0);
if (shared_msg == NULL) {
perror("In mmap()");
exit(1);
}
printf("Shared memory segment allocated correctly (%d bytes).\n", shared_seg_size);
rt_file = shared_msg->pt;
printf("rt_file : %s\n",rt_file);
rt_file = fopen ("res","a+");
printf("rt_file : %s\n", rt_file);
char x[10]="ABCDEFGHIJ";
fwrite(x, sizeof(x[0]), sizeof(x)/sizeof(x[0]), rt_file);
printf("Message type is %d, content is: %s\n", shared_msg->type, shared_msg->content);
if(shm_unlink(SHMOBJ_PATH) == -1){
printf("%s is used by another Process\n",SHMOBJ_PATH);
}
else{
printf("Memory is freed\n");
}
return 0;
}
FILE* pointers are valid only in the process where they were created.
While you can transfer the pointer value, or even the structure it points to, to another process, using it in the other process will invoke undefined behaviour.
If you want another process on the same machine to access a certain file I suggest that you send the file name, mode and offset to the other process and let it create it's own FILE* structure by calling fopen.

Writing struct to mapped memory file (mmap)

I have a problem to write struct into a mapped memory file.
I have two file namely mmap.write.c and mmap.read.c, and in these files, I'm writing an integer to a file and reading it from file.
When I want to write struct and read it, I could not think about that since in line 32 of mmap.write.c
sprintf((char*) file_memory, "%d\n", i);
and in line 25 of mmap.read.c
sscanf (file_memory, "%d", &integer);
There is no difference to write and read integer/double/float/char etc. since I can put pattern as second argument "%d" for integer. But what I will write here to indicate struct? That is my main problem.
The struct that I want to write and read:
#define CHANNELS 20
typedef dataholder struct {
int value[CHANNELS];
time_t time;
int hash;
}dataholder;
mmap.read.c
#include <stdlib.h>
#include <stdio.h>
#include <fcntl.h>
#include <sys/mman.h>
#include <sys/stat.h>
#include <unistd.h>
#include "mmap.h"
#define FILE_LENGTH 0x10000
int main (int argc, char* const argv[])
{
int fd;
void* file_memory;
int integer;
/* Open the file. */
fd = open (argv[1], O_RDWR, S_IRUSR | S_IWUSR);
printf("file opened\n");
/* Create the memory mapping. */
file_memory = mmap (0, FILE_LENGTH, PROT_READ | PROT_WRITE,
MAP_SHARED, fd, 0);
printf("memfile opened\n");
close (fd);
printf("file closed\n");
/* Read the integer, print it out, and double it. */
while(1) {
sscanf (file_memory, "%d", &integer);
printf ("value: %d\n", integer);
usleep(100000);
}
//sprintf ((char*) file_memory, "%d\n", 2 * integer);
/* Release the memory (unnecessary because the program exits). */
munmap (file_memory, FILE_LENGTH);
return 0;
}
mmap.write.c
#include <stdlib.h>
#include <stdio.h>
#include <fcntl.h>
#include <sys/mman.h>
#include <sys/stat.h>
#include <time.h>
#include <unistd.h>
#include "mmap.h"
#define FILE_LENGTH 0x10000
/* Return a uniformly random number in the range [low,high]. */
int random_range (unsigned const low, unsigned const high)
{
unsigned const range = high - low + 1;
return low + (int) (((double) range) * rand () / (RAND_MAX + 1.0));
}
int main (int argc, char* const argv[])
{
int fd, i;
void* file_memory;
/* Seed the random number generator. */
srand (time (NULL));
/* Prepare a file large enough to hold an unsigned integer. */
fd = open (argv[1], O_RDWR | O_CREAT | O_APPEND, S_IRUSR | S_IWUSR);
//lseek (fd, FILE_LENGTH+1, SEEK_SET);
write (fd, "", 1);
//lseek (fd, 0, SEEK_SET);
/* Create the memory mapping. */
file_memory = mmap (0, FILE_LENGTH, PROT_WRITE, MAP_SHARED, fd, 0);
close (fd);
/* Write a random integer to memory-mapped area. */
for(i=0; i<10000; i++) {
sprintf((char*) file_memory, "%d\n", i);
//goto a;
usleep(100000);
}
a:
/* Release the memory (unnecessary because the program exits). */
munmap (file_memory, FILE_LENGTH);
return 0;
}
Thanks a lot in advance.
First of all you have to keep track of where in the memory you want to write, second you have to remember that the mapped memory is just like any other pointer to memory. The last bit is important, as this means you can use normal array indexing to access the memory, or use functions such as memcpy to copy into the memory.
To write a structure, you have three choices:
Write the structure as-is, like in a binary file. This will mean you have to memcpy the structure to a specified position.
Write the structure, field-by-field, as text using e.g. sprintf to the correct position.
Treat the memory as one large string, and do e.g. sprintf of each field into a temporary buffer, then strcat to add it to the memory.
The simplest way is to just use a pointer:
dataholder *dh = file_memory;
/* now you can access dh->value, dh->time, dh->hash */
Since this struct doesn't contain any pointers, if you need to copy it in or out, you can just assign it, like:
dataholder dh_other = *dh;
or
*dh = dh_other;

Resources