poke-devel
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[PATCH v2] Add io space MMAP for memory mapping devices and files


From: Andreas Klinger
Subject: [PATCH v2] Add io space MMAP for memory mapping devices and files
Date: Fri, 5 Jan 2024 20:05:34 +0100

2024-01-05  Andreas Klinger  <ak@it-klinger.de>

        * libpoke/ios-dev-mmap.c: New file.
        * libpoke/Makefile.am (libpoke_la_SOURCES): Add ios-dev-mmap.c
        * libpoke/ios.c (IOS_DEV_MMAP): Define.
          (ios_dev_ifs): Initialize IOS_DEV_MMAP.
        * poke/pk-cmd-ios.c (pk_cmd_mmap): New function.
        * poke/pk-cmd.c (dot_cmds): Add mmap_cmd.
        * poke/pk-help.pk: Add help text for .mmap.
        * doc/poke.texi (mmap command): New section.
        * testsuite/Makefile.am (EXTRA_DIST): Add mmap-{1,2,3}.pk.
        * testsuite/poke.cmd/mmap-1.pk: New file.
        * testsuite/poke.cmd/mmap-2.pk: New file.
        * libpoke/ios-dev.h: New define IOD_EMMAP.
        * libpoke/libpoke.h: New define PK_IOD_EMMAP.
        * libpoke/std.pk: New function openmmap.
---

Thanks for the reviews, feedbacks and further tests on embedded hardware some
improvements could be implemented:
- coding conventions
- add test programms
- add openmmap helper function
- fix alignment issues when accessing memory mapped hardware registers, e. g.
  long @ 0x3#B need to be properly aligned
- add error messages via pk_printf()
- add error code IOD_EMMAP

Have fun!

 doc/poke.texi                |  42 ++++
 libpoke/Makefile.am          |   2 +-
 libpoke/ios-dev-mmap.c       | 405 +++++++++++++++++++++++++++++++++++
 libpoke/ios-dev.h            |   1 +
 libpoke/ios.c                |   3 +
 libpoke/libpoke.h            |   1 +
 libpoke/std.pk               |   6 +
 poke/pk-cmd-ios.c            |  51 +++++
 poke/pk-cmd.c                |   2 +
 poke/pk-help.pk              |  22 ++
 testsuite/Makefile.am        |   2 +
 testsuite/poke.cmd/mmap-1.pk |   7 +
 testsuite/poke.cmd/mmap-2.pk |   8 +
 13 files changed, 551 insertions(+), 1 deletion(-)
 create mode 100644 libpoke/ios-dev-mmap.c
 create mode 100644 testsuite/poke.cmd/mmap-1.pk
 create mode 100644 testsuite/poke.cmd/mmap-2.pk

diff --git a/doc/poke.texi b/doc/poke.texi
index 01ed802a..585cc19f 100644
--- a/doc/poke.texi
+++ b/doc/poke.texi
@@ -208,6 +208,7 @@ Dot-Commands
 * source command::              Executing commands in files.
 * file command::               Opening and selecting file IO spaces.
 * mem command::                        Opening and selecting memory IO spaces.
+* mmap command::               Opening and selecting memory mapped devices.
 * nbd command::                        Opening and selecting NBD IO spaces.
 * proc command::                Opening and selecting process IO spaces.
 * ios command::                        Switching between IO spaces.
@@ -8819,6 +8820,7 @@ au BufRead,BufNewFile *.pk set filetype=poke
 * source command::              Executing commands in files.
 * file command::               Opening and selecting file IO spaces.
 * mem command::                        Opening and selecting memory IO spaces.
+* mmap command::               Opening and selecting memory mapped devices.
 * nbd command::                        Opening and selecting NBD IO spaces.
 * proc command::                Opening and selecting process IO spaces.
 * sub command::                 Opening IO sub-spaces.
@@ -8931,6 +8933,46 @@ the buffer.
 When a new memory buffer IOS is opened it becomes the current IO
 space.  @xref{file command}.
 
+@node mmap command
+@section @code{.mmap}
+@cindex @code{.mmap}
+@cindex opening memory mapped device
+@cindex IO space
+The @command{.mmap} command opens a new IO space where the content is memory
+mapped from the device driver or file system. This is especially useful when a
+kernel driver offers a mmap function for mapping the content of kernel memory
+into userspace. The most famous example is the mem device with it's device node
+/dev/mem. But there are also many drivers especially in embedded systems using
+it.
+In the case of a regular file the mapping is done by the file system driver.
+The syntax is:
+
+@example
+.mmap @var{filename}, @var{base}, @var{size}
+@end example
+
+@noindent
+where @var{filename} is the name of the device node or the file name, 
@var{base}
+is the starting offset (or base address) of the mapping and @var{size} is the
+length of the mapped area.
+
+The @var{base} has to be a multiple of the mmu page size on the system. It can
+be retrieved via the c function getpagesize(). On most systems it's 4096 Bytes.
+
+When writing to the mapped area the portion which is written is memory synced
+with the syscall msync() after every write operation.
+
+For an example of mapping the gpio registers via /dev/mem on the Beaglebone
+black board and accessing the output enable (GPIO_OE) and data out
+(GPIO_DATAOUT) registers of the io memory:
+
+@example
+$ poke
+(poke) .mmap /dev/mem, 0x4804c000, 0x1000
+(poke) int @ 0x13C#B
+(poke) int @ 0x134#B
+@end example
+
 @node nbd command
 @section @code{.nbd}
 @cindex @code{.nbd}
diff --git a/libpoke/Makefile.am b/libpoke/Makefile.am
index f7a66113..71c4a0e6 100644
--- a/libpoke/Makefile.am
+++ b/libpoke/Makefile.am
@@ -62,7 +62,7 @@ libpoke_la_SOURCES = libpoke.h libpoke.c \
                      ios-dev-file.c ios-dev-mem.c \
                      ios-dev-zero.c ios-dev-sub.c \
                      ios-buffer.h ios-buffer.c \
-                     ios-dev-stream.c
+                     ios-dev-stream.c ios-dev-mmap.c
 
 libpoke_la_SOURCES += ../common/pk-utils.c ../common/pk-utils.h
 
diff --git a/libpoke/ios-dev-mmap.c b/libpoke/ios-dev-mmap.c
new file mode 100644
index 00000000..33fe11a2
--- /dev/null
+++ b/libpoke/ios-dev-mmap.c
@@ -0,0 +1,405 @@
+/* ios-dev_map.c - Memory mapped devices.  */
+
+/* Copyright (C) 2024 Andreas Klinger */
+
+/* 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 3 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.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+/* This file implements an IO device that can be used in order to edit
+   the memory mapped from device drivers via dev_map syscall.  */
+
+#include <config.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+/* We want 64-bit file offsets in all systems.  */
+#define _FILE_OFFSET_BITS 64
+
+#include <fcntl.h>
+#include <stdio.h>
+#include <string.h>
+#include <sys/mman.h>
+#include <sys/stat.h>
+#include <errno.h>
+
+#include "ios.h"
+#include "ios-dev.h"
+
+#include "pkt.h"
+
+/* State associated with a file device.  */
+struct ios_dev_mmap
+{
+  char *filename;
+  int fd;
+  int reg_file;
+  uint64_t flags;
+  int open_flags;
+  int prot;
+  uint64_t base;
+  uint64_t size;
+  void *addr;
+};
+
+static const char *
+ios_dev_mmap_get_if_name () {
+  return "MMAP";
+}
+
+static char *
+ios_dev_mmap_handler_normalize (const char *handler, uint64_t flags, int* 
error)
+{
+  char *new_handler = NULL;
+
+  if (strlen (handler) > 6
+      && handler[0] == 'm'
+      && handler[1] == 'm'
+      && handler[2] == 'a'
+      && handler[3] == 'p'
+      && handler[4] == ':'
+      && handler[5] == '/'
+      && handler[6] == '/')
+    {
+      new_handler = strdup (handler);
+      if (new_handler == NULL && error)
+        *error = IOD_ENOMEM;
+    }
+
+  if (error)
+    *error = IOD_OK;
+  return new_handler;
+}
+
+/* Returns 0 when the flags are inconsistent. */
+static inline int
+ios_dev_mmap_convert_flags_open (int mode_flags)
+{
+  int flags_for_open = 0;
+
+  if ((mode_flags & IOS_F_READ)
+      && (mode_flags & IOS_F_WRITE))
+    {
+      flags_for_open |= O_RDWR;
+    }
+  else if (mode_flags & IOS_F_READ)
+    {
+      flags_for_open |= O_RDONLY;
+    }
+  else if (mode_flags & IOS_F_WRITE)
+    {
+      flags_for_open |= O_WRONLY;
+    }
+  else
+    /* Cannot open a file neither to write nor to read.  */
+    return -1;
+
+  return flags_for_open;
+}
+
+/* Returns 0 when the flags are inconsistent. */
+static inline int
+ios_dev_mmap_convert_mmap_prot (int open_flags)
+{
+  int mmap_prot = 0;
+
+  if (open_flags & O_RDWR)
+    {
+      mmap_prot |= PROT_READ | PROT_WRITE;
+    }
+  else if (open_flags & O_RDONLY)
+    {
+      mmap_prot |= PROT_READ;
+    }
+  else if (open_flags & O_WRONLY)
+    {
+      mmap_prot |= PROT_WRITE;
+    }
+  else
+    /* Cannot dev_map neither to write nor to read.  */
+    return -1;
+
+  return mmap_prot;
+}
+
+static void *
+ios_dev_mmap_open (const char *handler, uint64_t flags, int *error,
+                   void *data __attribute__ ((unused)))
+{
+  struct ios_dev_mmap *dev_map = NULL;
+  int internal_error = IOD_ERROR;
+  uint8_t mode_flags = flags & IOS_FLAGS_MODE;
+  int open_flags = 0;
+  int fd;
+  const char *p;
+  char *end;
+  struct stat st;
+  int ret;
+
+  dev_map = malloc (sizeof (struct ios_dev_mmap));
+  if (!dev_map)
+    goto err;
+
+  memset (dev_map, 0, sizeof (struct ios_dev_mmap));
+
+  /* Format of handler:
+     mmap://BASE/SIZE/FILE-NAME  */
+
+  /* Skip the mmap:// */
+  p = handler + 7;
+
+  /* parse the base address of memory mapped area. This is an uint64.  */
+  dev_map->base = strtoull (p, &end, 0);
+  if (*p != '\0' && *end == '/')
+    /* Valid integer found.  */;
+  else
+    goto err;
+  p = end + 1;
+
+  /* parse the size of the memory mapped area. This is an uint64.  */
+  dev_map->size = strtoull (p, &end, 0);
+  if (*p != '\0' && *end == '/')
+    /* Valid integer found.  */;
+  else
+    goto err;
+  p = end + 1;
+
+  /* The rest of the string is the name, which may be empty.  */
+  dev_map->filename = strdup (p);
+  if (!p)
+    goto err;
+
+  /* Ok now do some validation.  */
+  /* base needs to be a multiple of PAGE_SIZE */
+  if (dev_map->base % getpagesize())
+    {
+      internal_error = IOD_EFLAGS;
+      goto err;
+    }
+
+  if (mode_flags)
+    {
+      /* Decide what mode to use to open the file.  */
+      open_flags = ios_dev_mmap_convert_flags_open (mode_flags);
+      if (open_flags == -1)
+        {
+          internal_error = IOD_EFLAGS;
+          goto err;
+        }
+      fd = open (dev_map->filename, open_flags);
+      if (fd == -1)
+        {
+          pk_printf ("Error in open of %s err: %s\n",
+                     dev_map->filename, strerror (errno));
+          goto err;
+        }
+      flags = mode_flags;
+    }
+  else
+    {
+      /* Try read-write initially.
+         If that fails, then try read-only.
+         If that fails, then try write-only.  */
+      open_flags = O_RDWR;
+      fd = open (dev_map->filename, open_flags);
+      flags |= (IOS_F_READ | IOS_F_WRITE);
+      if (fd == -1)
+        {
+          open_flags = O_RDONLY;
+          fd = open (dev_map->filename, open_flags);
+          if (fd != -1)
+            flags &= ~IOS_F_WRITE;
+        }
+      if (fd == -1)
+        {
+          open_flags = O_WRONLY;
+          fd = open (dev_map->filename, open_flags);
+          if (fd != -1)
+            flags &= ~IOS_F_READ;
+        }
+      if (fd == -1)
+        {
+          pk_printf ("Error in open of %s err: %s\n",
+                     dev_map->filename, strerror (errno));
+          goto err;
+        }
+    }
+
+  /* limit the size of the mapping for regular files for avoiding
+     SIGBUS when accessing memory outside of the file */
+  ret = fstat (fd, &st);
+  if (ret == -1)
+    {
+      pk_printf ("Error in fstat of %s err: %s\n",
+                 dev_map->filename, strerror (errno));
+      goto err;
+    }
+  if ((st.st_mode & S_IFMT) == S_IFREG)
+    dev_map->reg_file = 1;
+  else
+    dev_map->reg_file = 0;
+
+  if (dev_map->reg_file && (st.st_size < dev_map->size))
+    dev_map->size = st.st_size;
+
+  dev_map->fd = fd;
+  dev_map->flags = flags;
+  dev_map->open_flags = open_flags;
+  dev_map->prot = ios_dev_mmap_convert_mmap_prot (open_flags);
+
+  dev_map->addr = mmap (0, dev_map->size, dev_map->prot, MAP_SHARED,
+                        fd, dev_map->base);
+  if (dev_map->addr == MAP_FAILED)
+    {
+      pk_printf ("Error in mmap of %s base: 0x%x len: 0x%x prot: 0x%x err: 
%s\n",
+                 dev_map->filename, dev_map->base, dev_map->size,
+                 dev_map->prot, strerror (errno));
+      internal_error = IOD_EMMAP;
+      goto err;
+    }
+
+  if (error)
+    *error = IOD_OK;
+
+  return dev_map;
+
+err:
+  if (dev_map)
+    free (dev_map->filename);
+  free (dev_map);
+
+  if (error)
+    *error = internal_error;
+  return NULL;
+}
+
+static int
+ios_dev_mmap_close (void *iod)
+{
+  struct ios_dev_mmap *dev_map = iod;
+
+  munmap (dev_map->addr, dev_map->size);
+  close (dev_map->fd);
+
+  free (dev_map->filename);
+  free (dev_map);
+  return IOD_OK;
+}
+
+static uint64_t
+ios_dev_mmap_get_flags (void *iod)
+{
+  struct ios_dev_mmap *dev_map = iod;
+
+  return dev_map->flags;
+}
+
+static int
+ios_dev_mmap_pread (void *iod, void *buf, size_t count, ios_dev_off offset)
+{
+  struct ios_dev_mmap *dev_map = iod;
+  int align = count;
+  int spare = 0;
+
+  if ((offset + count) > dev_map->size)
+    return IOD_EOF;
+
+  if (align > 8)
+    align = 8;
+
+  if (align > 1 && offset % align)
+    {
+      void *tmp;
+      spare = offset % align;
+      tmp = malloc (count + align);
+      memcpy (tmp, dev_map->addr + offset - spare, count + align);
+      memcpy (buf, tmp + spare, count);
+      free (tmp);
+    }
+  else
+    memcpy (buf, dev_map->addr + offset, count);
+
+  return IOD_OK;
+}
+
+static int
+ios_dev_mmap_pwrite (void *iod, const void *buf, size_t count,
+                     ios_dev_off offset)
+{
+  struct ios_dev_mmap *dev_map = iod;
+  int align = count;
+
+  if ((offset + count) > dev_map->size)
+    return IOD_EOF;
+
+  if (align > 8)
+    align = 8;
+
+  if (align > 1 && offset % align)
+    {
+      void *tmp;
+      int spare = 0;
+      spare = offset % align;
+      tmp = malloc (count + spare);
+      memcpy (tmp, dev_map->addr + offset - spare, align);
+      memcpy (tmp + spare, buf, count);
+      memcpy (tmp + spare + count, dev_map->addr + offset + count - spare, 
align);
+      memcpy (dev_map->addr + offset - spare, tmp, count + align);
+      free (tmp);
+    }
+  else
+    memcpy (dev_map->addr + offset, buf, count);
+
+  return IOD_OK;
+}
+
+static ios_dev_off
+ios_dev_mmap_size (void *iod)
+{
+  struct ios_dev_mmap *dev_map = iod;
+
+  return dev_map->size;
+}
+
+static int
+ios_dev_mmap_flush (void *iod, ios_dev_off offset)
+{
+  struct ios_dev_mmap *dev_map = iod;
+  int ret;
+
+  if (dev_map->reg_file)
+    {
+      ret = msync (dev_map->addr, dev_map->size, MS_SYNC);
+      if (ret == -1)
+        {
+          pk_printf ("Error in msync of %s base: 0x%lx len: 0x%lx err: %s\n",
+                     dev_map->filename, dev_map->addr, dev_map->size,
+                     strerror (errno));
+        }
+    }
+
+  return IOS_OK;
+}
+
+struct ios_dev_if ios_dev_mmap =
+  {
+   .get_if_name = ios_dev_mmap_get_if_name,
+   .handler_normalize = ios_dev_mmap_handler_normalize,
+   .open = ios_dev_mmap_open,
+   .close = ios_dev_mmap_close,
+   .pread = ios_dev_mmap_pread,
+   .pwrite = ios_dev_mmap_pwrite,
+   .get_flags = ios_dev_mmap_get_flags,
+   .size = ios_dev_mmap_size,
+   .flush = ios_dev_mmap_flush
+  };
diff --git a/libpoke/ios-dev.h b/libpoke/ios-dev.h
index fe24fd23..420b749a 100644
--- a/libpoke/ios-dev.h
+++ b/libpoke/ios-dev.h
@@ -45,6 +45,7 @@ typedef uint64_t ios_dev_off;
 #define IOD_ENOMEM -4 /* Memory allocation failure.  */
 #define IOD_EOF    -5 /* End of file / input.  */
 #define IOD_EINVAL -6 /* Invalid argument.  */
+#define IOD_EMMAP  -7 /* Memory mapping error.  */
 
 /* Each IO backend should implement a device interface, by filling an
    instance of the struct defined below.
diff --git a/libpoke/ios.c b/libpoke/ios.c
index 48719c6a..c88a1c41 100644
--- a/libpoke/ios.c
+++ b/libpoke/ios.c
@@ -103,6 +103,7 @@ extern struct ios_dev_if ios_dev_nbd; /* ios-dev-nbd.c */
 extern struct ios_dev_if ios_dev_proc; /* ios-dev-proc.c */
 #endif
 extern struct ios_dev_if ios_dev_sub; /* ios-dev-sub.c */
+extern struct ios_dev_if ios_dev_mmap; /* ios-dev-mmap.c */
 
 enum
 {
@@ -112,6 +113,7 @@ enum
   IOS_DEV_NBD,
   IOS_DEV_PROC,
   IOS_DEV_SUB,
+  IOS_DEV_MMAP,
   IOS_DEV_FILE, /* File must be last */
 };
 
@@ -131,6 +133,7 @@ static const struct ios_dev_if *ios_dev_ifs[] =
     [IOS_DEV_PROC] = NULL,
 #endif
     [IOS_DEV_SUB] = &ios_dev_sub,
+    [IOS_DEV_MMAP] = &ios_dev_mmap,
     [IOS_DEV_FILE] = &ios_dev_file, /* File must be last */
   };
 
diff --git a/libpoke/libpoke.h b/libpoke/libpoke.h
index 4c5e8918..623b7e19 100644
--- a/libpoke/libpoke.h
+++ b/libpoke/libpoke.h
@@ -1310,6 +1310,7 @@ typedef uint64_t pk_iod_off;
 #define PK_IOD_ENOMEM -4
 #define PK_IOD_EOF    -5
 #define PK_IOD_EINVAL -6
+#define PK_IOD_EMMAP  -7
 
 struct pk_iod_if
 {
diff --git a/libpoke/std.pk b/libpoke/std.pk
index ac2397db..ce8245f2 100644
--- a/libpoke/std.pk
+++ b/libpoke/std.pk
@@ -435,6 +435,12 @@ fun openproc = (uint<64> pid, uint<64> flags = 0) int<32>:
   return open (format ("pid://%u64d", pid), flags);
 }
 
+fun openmmap =
+  (string path, offset<uint<64>,B> base, offset<uint<64>,B> size) int<32>:
+{
+  return open (format ("mmap://%u64d/%u64d/%s", base/#B, size/#B, path));
+}
+
 /*** Miscellanea.  */
 
 var NULL = 0#B;
diff --git a/poke/pk-cmd-ios.c b/poke/pk-cmd-ios.c
index 1435266f..47dc4719 100644
--- a/poke/pk-cmd-ios.c
+++ b/poke/pk-cmd-ios.c
@@ -576,6 +576,53 @@ pk_cmd_nbd (int argc, struct pk_cmd_arg argv[], uint64_t 
uflags)
 }
 #endif /* HAVE_LIBNBD */
 
+static int
+pk_cmd_mmap (int argc, struct pk_cmd_arg argv[], uint64_t uflags)
+{
+  /* mmap FILENAME BASE SIZE */
+  uint64_t base, size;
+  char *handler;
+  int ios_id;
+
+  assert (argc == 4);
+  assert (PK_CMD_ARG_TYPE (argv[1]) == PK_CMD_ARG_STR);
+
+  /* Create a new IO space.  */
+  const char *filename = PK_CMD_ARG_STR (argv[1]);
+
+  assert (PK_CMD_ARG_TYPE (argv[2]) == PK_CMD_ARG_INT);
+  base = PK_CMD_ARG_INT (argv[2]);
+
+  assert (PK_CMD_ARG_TYPE (argv[3]) == PK_CMD_ARG_INT);
+  size = PK_CMD_ARG_INT (argv[3]);
+
+  if (access (filename, F_OK) == 0)
+
+  if (pk_ios_search (poke_compiler, filename, PK_IOS_SEARCH_F_EXACT) != NULL)
+    {
+      printf (_("File %s already opened.  Use `.ios IOS' to switch.\n"),
+              filename);
+      return 0;
+    }
+
+  /* Build the handler for the mmap IOS.  */
+  if (asprintf (&handler, "mmap://0x%" PRIx64 "/0x%" PRIx64 "/%s",
+                           base, size, filename) == -1)
+    return 0;
+
+  /* Open the IOS.  */
+  ios_id = pk_ios_open (poke_compiler, handler, 0, 1);
+  if (ios_id == PK_IOS_NOID)
+    {
+      pk_printf (_("Error creating mmap IOS %s\n"), handler);
+      free (handler);
+      return 0;
+    }
+  free (handler);
+
+  return 1;
+}
+
 const struct pk_cmd ios_cmd =
   {"ios", "?s", "", 0, NULL, NULL, pk_cmd_ios, ".ios IOS", 
poke_completion_function};
 
@@ -598,6 +645,10 @@ const struct pk_cmd nbd_cmd =
   {"nbd", "s", "", 0, NULL, NULL, pk_cmd_nbd, ".nbd URI", NULL};
 #endif
 
+const struct pk_cmd mmap_cmd =
+  {"mmap", "s,i,i", "", 0, NULL, NULL, pk_cmd_mmap, ".mmap FILENAME, BASE, 
SIZE",
+   NULL};
+
 const struct pk_cmd close_cmd =
   {"close", "s", "", PK_CMD_F_REQ_IO, NULL, NULL, pk_cmd_close,
    ".close [IOS]", poke_completion_function};
diff --git a/poke/pk-cmd.c b/poke/pk-cmd.c
index e6825423..ddc1ca85 100644
--- a/poke/pk-cmd.c
+++ b/poke/pk-cmd.c
@@ -48,6 +48,7 @@ extern const struct pk_cmd mem_cmd; /* pk-cmd-ios.c */
 #ifdef HAVE_LIBNBD
 extern const struct pk_cmd nbd_cmd; /* pk-cmd-ios.c */
 #endif
+extern const struct pk_cmd mmap_cmd; /* pk-cmd-mmap.c */
 extern const struct pk_cmd close_cmd; /* pk-cmd-file.c */
 extern const struct pk_cmd load_cmd; /* pk-cmd-file.c */
 extern const struct pk_cmd source_cmd; /* pk-cmd-ios.c */
@@ -91,6 +92,7 @@ static const struct pk_cmd *dot_cmds[] =
 #ifdef HAVE_LIBNBD
     &nbd_cmd,
 #endif
+    &mmap_cmd,
     &null_cmd
   };
 
diff --git a/poke/pk-help.pk b/poke/pk-help.pk
index e5129e2d..b7b35e06 100644
--- a/poke/pk-help.pk
+++ b/poke/pk-help.pk
@@ -245,6 +245,28 @@ Create a IO space providing access to a Network Block 
Device
 identified by the given URI."
     };
 
+pk_help_add_topic
+  :entry Poke_HelpEntry {
+      category = "dot-commands",
+      topic = ".mmap",
+      synopsis = ".mmap FILENAME, BASE, SIZE",
+      summary = "open a device driver or file with memory mapping",
+      description = "\
+Create a IO space providing access to a device driver with mmap function
+or also a file where the mmap is provided by the file system driver.
+
+.mmap /dev/mem, BASE, SIZE
+Mapps physical memory area at BASE address which have to be
+a multiple of the page size.
+
+.mmap /dev/mem, 0x4804c000, 0x1000
+int @ 0x13C#B
+int @ 0x134#B
+Example on a Beaglebone black for watching gpio registers and possibly further
+changing them.
+"
+    };
+
 pk_help_add_topic
   :entry Poke_HelpEntry {
       category = "dot-commands",
diff --git a/testsuite/Makefile.am b/testsuite/Makefile.am
index ae6fb924..3d66e9a3 100644
--- a/testsuite/Makefile.am
+++ b/testsuite/Makefile.am
@@ -95,6 +95,8 @@ EXTRA_DIST = \
   poke.cmd/maps-8.pk \
   poke.cmd/maps-9.pk \
   poke.cmd/maps-alien-1.pk \
+  poke.cmd/mmap-1.pk \
+  poke.cmd/mmap-2.pk \
   poke.cmd/nbd-1.pk \
   poke.cmd/save-1.pk \
   poke.cmd/save-2.pk \
diff --git a/testsuite/poke.cmd/mmap-1.pk b/testsuite/poke.cmd/mmap-1.pk
new file mode 100644
index 00000000..618008d6
--- /dev/null
+++ b/testsuite/poke.cmd/mmap-1.pk
@@ -0,0 +1,7 @@
+/* { dg-do run } */
+
+/* Check that it's possible to memory map /dev/zero. */
+
+/* { dg-command { .mmap /dev/zero,0x0,0x100} } */
+/* { dg-command { dump :from 0#B :size 4#B :ruler 0 :ascii 0} } */
+/* { dg-output "00000000: 0000 0000" } */
diff --git a/testsuite/poke.cmd/mmap-2.pk b/testsuite/poke.cmd/mmap-2.pk
new file mode 100644
index 00000000..3d27918d
--- /dev/null
+++ b/testsuite/poke.cmd/mmap-2.pk
@@ -0,0 +1,8 @@
+/* { dg-do run } */
+/* { dg-data {c*} {0x10 0x20 0x30 0x40 0x50 0x60 0x70 0x80} foo.data } */
+
+/* Check that it's possible to memory map a regular file. */
+
+/* { dg-command { .mmap foo.data,0x0,0x100} } */
+/* { dg-command { dump :from 0#B :size 4#B :ruler 0 :ascii 0} } */
+/* { dg-output "00000000: 1020 3040" } */
-- 
2.39.2

Attachment: signature.asc
Description: PGP signature


reply via email to

[Prev in Thread] Current Thread [Next in Thread]