Add support to map the contents of a file
Add a package HW.File with a single procedure Map():
procedure Map
(Path : in String;
Addr : in Word64;
Len : in Natural;
Readable : in Boolean := False;
Writable : in Boolean := False;
Map_Copy : in Boolean := False;
Success : out Boolean)
with
Pre => (Readable or Writable) and
(if Map_Copy then Readable and not Writable);
If `Map_Copy` is `False`, it should map `Len` bytes from the start of
the file given by `Path` into the application's address space at `Addr`
using mmap(). If `Map_Copy` is `True`, anonymous memory should be map-
ped instead and be filled with a copy of the file's content using
read().
The current implementation is backed by C code to reduce dependencies
to external libraries (e.g. Florist is not packaged by a famous Linux
distro).
While we are at it, also add a configuration file for common POSIX
environments (configs/posix).
Change-Id: Ic10c35b35d3216dab6a5b2baba7ba619c885b346
Signed-off-by: Nico Huber <nico.h@gmx.de>
Reviewed-on: https://review.coreboot.org/18779
Reviewed-by: Stefan Reinauer <stefan.reinauer@coreboot.org>
diff --git a/c/hw-file.c b/c/hw-file.c
new file mode 100644
index 0000000..4d756ea
--- /dev/null
+++ b/c/hw-file.c
@@ -0,0 +1,103 @@
+/*
+ * Copyright (C) 2017 Nico Huber <nico.h@gmx.de>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 General Public License for more details.
+ */
+
+#include <stdint.h>
+#include <sys/mman.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <errno.h>
+
+#define HW_FILE_READ 0x01
+#define HW_FILE_WRITE 0x02
+
+static int map_file(const char *const path,
+ const uint64_t addr,
+ const uint32_t len,
+ const uint32_t mode)
+{
+ const int prot = (mode & HW_FILE_READ ? PROT_READ : 0) |
+ (mode & HW_FILE_WRITE ? PROT_WRITE : 0);
+
+ if (mode & ~(HW_FILE_READ | HW_FILE_WRITE) ||
+ !(mode & (HW_FILE_READ | HW_FILE_WRITE)))
+ return EINVAL;
+
+ const int fd = open(path, mode & HW_FILE_WRITE ? O_RDWR : O_RDONLY);
+ if (fd < 0)
+ return errno;
+
+ void *const mapped = mmap((void *)(uintptr_t)addr, len, prot,
+ MAP_SHARED | MAP_FIXED, fd, (off_t)0);
+ close(fd);
+ if (mapped == MAP_FAILED)
+ return errno;
+
+ return 0;
+}
+
+static int map_fill_from_file(const char *const path,
+ const uint64_t addr,
+ const uint32_t len,
+ const uint32_t mode)
+{
+ uint32_t xferred;
+ ssize_t read_ret;
+
+ if (mode != HW_FILE_READ)
+ return EINVAL;
+
+ void *const mapped = mmap((void *)(uintptr_t)addr, len,
+ PROT_READ | PROT_WRITE,
+ MAP_ANONYMOUS | MAP_PRIVATE | MAP_FIXED,
+ -1, (off_t)0);
+ if (mapped == MAP_FAILED)
+ return errno;
+
+ const int fd = open(path, O_RDONLY);
+ if (fd < 0)
+ goto _munmap;
+
+ xferred = 0;
+ do {
+ read_ret = read(fd, (uint8_t *)mapped + xferred, len - xferred);
+ if (read_ret > 0)
+ xferred += read_ret;
+ } while ((read_ret > 0 || (read_ret == -1 && errno == EINTR))
+ && xferred < len);
+ close(fd);
+
+ if (xferred < len)
+ goto _munmap;
+
+ if (mprotect(mapped, len, PROT_READ))
+ goto _munmap;
+
+ return 0;
+
+_munmap:
+ munmap(mapped, len);
+ return errno;
+}
+
+int hw_file_map(const char *const path,
+ const uint64_t addr,
+ const uint32_t len,
+ const uint32_t mode,
+ const int copy)
+{
+ if (copy)
+ return map_fill_from_file(path, addr, len, mode);
+ else
+ return map_file(path, addr, len, mode);
+}