/* * Copyright (C) 2009 Gilles Chanteperdrix . * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "current.h" #include "umm.h" #include "internal.h" struct xnvdso *cobalt_vdso; void *cobalt_umm_private = NULL; void *cobalt_umm_shared = NULL; static pthread_once_t init_bind_once = PTHREAD_ONCE_INIT; static uint32_t private_size; static void *__map_umm(const char *name, uint32_t *size_r) { struct cobalt_memdev_stat statbuf; int fd, ret; void *addr; fd = __RT(open(name, O_RDWR)); if (fd < 0) { early_warning("cannot open RTDM device %s: %s", name, strerror(errno)); return MAP_FAILED; } ret = __RT(ioctl(fd, MEMDEV_RTIOC_STAT, &statbuf)); if (ret) { __RT(close(fd)); early_warning("failed getting status of %s: %s", name, strerror(errno)); return MAP_FAILED; } addr = __RT(mmap(NULL, statbuf.size, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0)); __RT(close(fd)); *size_r = statbuf.size; return addr; } #define map_umm(__name, __size_r) __map_umm("/dev/rtdm/" __name, __size_r) void cobalt_unmap_umm(void) { void *addr; /* * Remapping the private heap must be done after the process * has re-attached to the Cobalt core, in order to reinstate a * proper private heap, Otherwise the global heap would be * used instead, leading to unwanted effects. * * On machines without an MMU, there is no such thing as fork. * * We replace former mappings with an invalid one, to detect * any spurious late access. */ addr = __STD(mmap(cobalt_umm_private, private_size, PROT_NONE, MAP_PRIVATE | MAP_ANONYMOUS | MAP_FIXED, -1, 0)); if (addr != cobalt_umm_private) munmap(cobalt_umm_private, private_size); cobalt_umm_private = NULL; init_bind_once = PTHREAD_ONCE_INIT; } /* * Will be called once on behalf of xenomai_init(), and when * re-binding after a fork. */ static void init_bind(void) { cobalt_umm_private = map_umm(COBALT_MEMDEV_PRIVATE, &private_size); if (cobalt_umm_private == MAP_FAILED) { early_warning("cannot map private umm area: %s", strerror(errno)); early_panic("(CONFIG_DEVTMPFS_MOUNT not enabled?)"); } } /* Will be called only once, upon call to xenomai_init(). */ static void init_loadup(__u32 vdso_offset) { uint32_t size; cobalt_umm_shared = map_umm(COBALT_MEMDEV_SHARED, &size); if (cobalt_umm_shared == MAP_FAILED) early_panic("cannot map shared umm area: %s", strerror(errno)); cobalt_vdso = (struct xnvdso *)(cobalt_umm_shared + vdso_offset); } void cobalt_init_umm(__u32 vdso_offset) { pthread_once(&init_bind_once, init_bind); init_loadup(vdso_offset); }