建立工程,成功创建两个虚拟串口
This commit is contained in:
288
source/OpenAMP/libmetal/lib/system/linux/utilities.c
Normal file
288
source/OpenAMP/libmetal/lib/system/linux/utilities.c
Normal file
@@ -0,0 +1,288 @@
|
||||
/*
|
||||
* Copyright (c) 2015, Xilinx Inc. and Contributors. All rights reserved.
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-3-Clause
|
||||
*/
|
||||
|
||||
/*
|
||||
* @file utils.c
|
||||
* @brief Linux libmetal utility functions.
|
||||
*/
|
||||
|
||||
#include <metal/utilities.h>
|
||||
#include <metal/sys.h>
|
||||
|
||||
/**
|
||||
* @brief Open (or create) a file.
|
||||
*
|
||||
* This function opens or creates a file with read/write permissions and the
|
||||
* O_CLOEXEC flag set.
|
||||
*
|
||||
* @param[in] path File path to open.
|
||||
* @param[in] shm Open shared memory (via shm_open) if non-zero.
|
||||
* @return File descriptor.
|
||||
*/
|
||||
int metal_open(const char *path, int shm)
|
||||
{
|
||||
const int flags = O_RDWR | O_CREAT | O_CLOEXEC;
|
||||
const int mode = S_IRUSR | S_IWUSR;
|
||||
int fd;
|
||||
|
||||
if (!path || !strlen(path))
|
||||
return -EINVAL;
|
||||
|
||||
fd = shm ? shm_open(path, flags, mode) : open(path, flags, mode);
|
||||
return fd < 0 ? -errno : fd;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Open (or create) and unlink a file.
|
||||
*
|
||||
* This function opens or creates a file with read/write permissions and the
|
||||
* O_CLOEXEC flag set. This file is then unlinked to ensure that it is removed
|
||||
* when the last reference to the file is dropped. This ensures that libmetal
|
||||
* shared maps are released appropriately once all users of the shared data
|
||||
* exit.
|
||||
*
|
||||
* @param[in] path File path to open.
|
||||
* @param[in] shm Open shared memory (via shm_open) if non-zero.
|
||||
* @return File descriptor.
|
||||
*/
|
||||
int metal_open_unlinked(const char *path, int shm)
|
||||
{
|
||||
int fd, error;
|
||||
|
||||
fd = metal_open(path, shm);
|
||||
if (fd < 0)
|
||||
return fd;
|
||||
|
||||
error = shm ? shm_unlink(path) : unlink(path);
|
||||
error = error < 0 ? -errno : 0;
|
||||
if (error)
|
||||
close(fd);
|
||||
|
||||
return error ? error : fd;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Randomize a string.
|
||||
*
|
||||
* This function randomizes the contents of a string.
|
||||
*
|
||||
* @param[in] template String to be randomized.
|
||||
*/
|
||||
void metal_randomize_string(char *template)
|
||||
{
|
||||
const char *chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
|
||||
"abcdefghijklmnopqrstuvwxyz"
|
||||
"0123456789-=";
|
||||
while (*template) {
|
||||
*template++ = chars[rand() % 64];
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Create a file name template suitable for use with metal_mktemp.
|
||||
*
|
||||
* @param[out] template Template string to be filled in.
|
||||
* @param[in] name Module/user identifier used as part of the
|
||||
* generated template.
|
||||
*/
|
||||
void metal_mktemp_template(char template[PATH_MAX], const char *name)
|
||||
{
|
||||
snprintf(template, PATH_MAX, "%s/metal-%s-XXXXXX",
|
||||
_metal.tmp_path, name);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Create a temporary file or fifo.
|
||||
*
|
||||
* This function creates a temporary file or fifo, and sets the O_CLOEXEC flag
|
||||
* on it.
|
||||
*
|
||||
* @param[in] template File name template (the last 6 characters must
|
||||
* be XXXXXX per mkstemp requirements).
|
||||
* @param[in] fifo Non-zero to create a FIFO instead of a regular
|
||||
* file.
|
||||
* @return File descriptor.
|
||||
*/
|
||||
int metal_mktemp(char *template, int fifo)
|
||||
{
|
||||
const int mode = S_IRUSR | S_IWUSR;
|
||||
int result, len, flags;
|
||||
char *suffix;
|
||||
|
||||
if (!template)
|
||||
return -EINVAL;
|
||||
|
||||
len = strlen(template);
|
||||
suffix = &template[len - 6];
|
||||
if (len < 6 || strcmp(suffix, "XXXXXX")) {
|
||||
metal_log(METAL_LOG_ERROR, "template %s has no trailing pattern\n",
|
||||
template);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
flags = (fifo
|
||||
? O_RDONLY | O_NONBLOCK | O_CLOEXEC
|
||||
: O_CREAT | O_EXCL | O_RDWR | O_CLOEXEC);
|
||||
|
||||
for (;;) {
|
||||
metal_randomize_string(suffix);
|
||||
if (fifo) {
|
||||
result = mkfifo(template, mode);
|
||||
if (result < 0) {
|
||||
if (errno == EEXIST)
|
||||
continue;
|
||||
metal_log(METAL_LOG_ERROR, "mkfifo(%s) failed (%s)\n",
|
||||
template, strerror(errno));
|
||||
return -errno;
|
||||
}
|
||||
}
|
||||
|
||||
result = open(template, flags, mode);
|
||||
if (result < 0) {
|
||||
if (fifo)
|
||||
unlink(template);
|
||||
if (errno == EEXIST)
|
||||
continue;
|
||||
metal_log(METAL_LOG_ERROR, "open() failed (%s)\n",
|
||||
strerror(errno));
|
||||
return -errno;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Open (or create) and unlink a temporary file.
|
||||
*
|
||||
* This function creates a temporary file, and sets the O_CLOEXEC flag on it.
|
||||
* O_CLOEXEC flag set. This file is then unlinked to ensure that it is removed
|
||||
* when the last reference to the file is dropped. This ensures that libmetal
|
||||
* shared maps are released appropriately once all users of the shared data
|
||||
* exit.
|
||||
*
|
||||
* @param[in] template File name template (the last 6 characters must
|
||||
* be XXXXXX per mkstemp requirements).
|
||||
* @return File descriptor.
|
||||
*/
|
||||
int metal_mktemp_unlinked(char *template)
|
||||
{
|
||||
int fd, error;
|
||||
|
||||
fd = metal_mktemp(template, 0);
|
||||
if (fd < 0)
|
||||
return fd;
|
||||
|
||||
error = unlink(template) < 0 ? -errno : 0;
|
||||
if (error)
|
||||
close(fd);
|
||||
|
||||
return error ? error : fd;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Map a segment of a file/device.
|
||||
*
|
||||
* This function maps a segment of a file or device into the process address
|
||||
* space, after optionally expanding the file if necessary. If required, the
|
||||
* file is expanded to hold the requested map area. This is done under and
|
||||
* advisory lock, and therefore the called must not have an advisory lock on
|
||||
* the file being mmapped.
|
||||
*
|
||||
* @param[in] fd File descriptor to map.
|
||||
* @param[in] offset Offset in file to map.
|
||||
* @param[in] size Size of region to map.
|
||||
* @param[in] expand Allow file expansion via ftruncate if non-zero.
|
||||
* @param[in] flags Flags for mmap(), MAP_SHARED included implicitly.
|
||||
* @param[out] result Returned pointer to new memory map.
|
||||
* @return 0 on success, or -errno on error.
|
||||
*/
|
||||
int metal_map(int fd, off_t offset, size_t size, int expand, int flags,
|
||||
void **result)
|
||||
{
|
||||
int prot = PROT_READ | PROT_WRITE, error;
|
||||
void *mem;
|
||||
|
||||
flags |= MAP_SHARED;
|
||||
|
||||
if (fd < 0) {
|
||||
fd = -1;
|
||||
flags = MAP_PRIVATE | MAP_ANONYMOUS;
|
||||
} else if (expand) {
|
||||
off_t reqsize = offset + size;
|
||||
struct stat stat;
|
||||
|
||||
error = flock(fd, LOCK_EX) < 0 ? -errno : 0;
|
||||
if (!error)
|
||||
error = fstat(fd, &stat);
|
||||
if (!error && stat.st_size < reqsize)
|
||||
error = ftruncate(fd, reqsize);
|
||||
if (!error)
|
||||
flock(fd, LOCK_UN);
|
||||
if (error)
|
||||
return -errno;
|
||||
}
|
||||
|
||||
mem = mmap(NULL, size, prot, flags, fd, offset);
|
||||
if (mem == MAP_FAILED)
|
||||
return -errno;
|
||||
*result = mem;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Unmap a segment of the process address space.
|
||||
*
|
||||
* This function unmaps a segment of the process address space.
|
||||
*
|
||||
* @param[in] mem Segment to unmap.
|
||||
* @param[in] size Size of region to unmap.
|
||||
* @return 0 on success, or -errno on error.
|
||||
*/
|
||||
int metal_unmap(void *mem, size_t size)
|
||||
{
|
||||
return munmap(mem, size) < 0 ? -errno : 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Lock in a region of the process address space.
|
||||
*
|
||||
* @param[in] mem Pointer to start of region.
|
||||
* @param[in] size Size of region.
|
||||
* @return 0 on success, or -errno on error.
|
||||
*/
|
||||
int metal_mlock(void *mem, size_t size)
|
||||
{
|
||||
return mlock(mem, size) ? -errno : 0;
|
||||
}
|
||||
|
||||
int metal_virt2phys(void *addr, unsigned long *phys)
|
||||
{
|
||||
off_t offset;
|
||||
uint64_t entry;
|
||||
int error;
|
||||
|
||||
if (_metal.pagemap_fd < 0)
|
||||
return -ENOSYS;
|
||||
|
||||
offset = ((uintptr_t)addr >> _metal.page_shift) * sizeof(entry);
|
||||
error = pread(_metal.pagemap_fd, &entry, sizeof(entry), offset);
|
||||
if (error < 0) {
|
||||
metal_log(METAL_LOG_ERROR, "failed pagemap pread (offset %llx) - %s\n",
|
||||
(unsigned long long)offset, strerror(errno));
|
||||
return -errno;
|
||||
}
|
||||
|
||||
/* Check page present and not swapped. */
|
||||
if ((entry >> 62) != 2) {
|
||||
metal_log(METAL_LOG_ERROR, "pagemap page not present, %llx -> %llx\n",
|
||||
(unsigned long long)offset, (unsigned long long)entry);
|
||||
return -ENOENT;
|
||||
}
|
||||
|
||||
*phys = (entry & ((1ULL << 54) - 1)) << _metal.page_shift;
|
||||
return 0;
|
||||
}
|
Reference in New Issue
Block a user