1 /*
2  * Copyright (c) 2015, Xilinx Inc. and Contributors. All rights reserved.
3  *
4  * SPDX-License-Identifier: BSD-3-Clause
5  */
6 
7 /*
8  * @file	utils.c
9  * @brief	Linux libmetal utility functions.
10  */
11 
12 #include <metal/utilities.h>
13 #include <metal/sys.h>
14 
15 /**
16  * @brief	Open (or create) a file.
17  *
18  * This function opens or creates a file with read/write permissions and the
19  * O_CLOEXEC flag set.
20  *
21  * @param[in]	path	File path to open.
22  * @param[in]	shm	Open shared memory (via shm_open) if non-zero.
23  * @return	File descriptor.
24  */
metal_open(const char * path,int shm)25 int metal_open(const char *path, int shm)
26 {
27 	const int flags = O_RDWR | O_CREAT | O_CLOEXEC;
28 	const int mode = S_IRUSR | S_IWUSR;
29 	int fd;
30 
31 	if (!path || !strlen(path))
32 		return -EINVAL;
33 
34 	fd = shm ? shm_open(path, flags, mode) : open(path, flags, mode);
35 	return fd < 0 ? -errno : fd;
36 }
37 
38 /**
39  * @brief	Map a segment of a file/device.
40  *
41  * This function maps a segment of a file or device into the process address
42  * space, after optionally expanding the file if necessary.  If required, the
43  * file is expanded to hold the requested map area.  This is done under and
44  * advisory lock, and therefore the called must not have an advisory lock on
45  * the file being mmapped.
46  *
47  * @param[in]	fd	File descriptor to map.
48  * @param[in]	offset	Offset in file to map.
49  * @param[in]	size	Size of region to map.
50  * @param[in]	expand	Allow file expansion via ftruncate if non-zero.
51  * @param[in]	flags	Flags for mmap(), MAP_SHARED included implicitly.
52  * @param[out]	result	Returned pointer to new memory map.
53  * @return	0 on success, or -errno on error.
54  */
metal_map(int fd,off_t offset,size_t size,int expand,int flags,void ** result)55 int metal_map(int fd, off_t offset, size_t size, int expand, int flags,
56 	      void **result)
57 {
58 	int prot = PROT_READ | PROT_WRITE, error;
59 	void *mem;
60 
61 	flags |= MAP_SHARED;
62 
63 	if (fd < 0) {
64 		fd = -1;
65 		flags = MAP_PRIVATE | MAP_ANONYMOUS;
66 	} else if (expand) {
67 		off_t reqsize = offset + size;
68 		struct stat stat;
69 
70 		error = flock(fd, LOCK_EX) < 0 ? -errno : 0;
71 		if (!error)
72 			error = fstat(fd, &stat);
73 		if (!error && stat.st_size < reqsize)
74 			error = ftruncate(fd, reqsize);
75 		if (!error)
76 			flock(fd, LOCK_UN);
77 		if (error)
78 			return -errno;
79 	}
80 
81 	mem = mmap(NULL, size, prot, flags, fd, offset);
82 	if (mem == MAP_FAILED)
83 		return -errno;
84 	*result = mem;
85 	return 0;
86 }
87 
88 /**
89  * @brief	Unmap a segment of the process address space.
90  *
91  * This function unmaps a segment of the process address space.
92  *
93  * @param[in]	mem	Segment to unmap.
94  * @param[in]	size	Size of region to unmap.
95  * @return	0 on success, or -errno on error.
96  */
metal_unmap(void * mem,size_t size)97 int metal_unmap(void *mem, size_t size)
98 {
99 	return munmap(mem, size) < 0 ? -errno : 0;
100 }
101