poke-devel
[Top][All Lists]
Advanced

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

Re: [PATCH v3] Add io space MMAP for memory mapping devices and files


From: Jose E. Marchesi
Subject: Re: [PATCH v3] Add io space MMAP for memory mapping devices and files
Date: Fri, 12 Jan 2024 16:01:33 +0100
User-agent: Gnus/5.13 (Gnus v5.13)

Hello Andreas.

This is looking good! :)
Just a few little comments below.

> 2024-01-12  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 and feedback.
>
> Changes to v2 are:
> - Test if mmap is available (HAVE_MMAP)
> - Function openmmap
> - Test for /dev/zero in testsuite ("memzero")
> - remove memcpy() in IOD due to alignment issues
> - test .mmap with new pread and pwrite functions the access to hardware
>   registers on x86-64, arm and aarch64.
>
>  configure.ac                 |   5 +
>  doc/poke.texi                |  42 ++++
>  libpoke/Makefile.am          |   4 +
>  libpoke/ios-dev-mmap.c       | 459 +++++++++++++++++++++++++++++++++++
>  libpoke/ios-dev.h            |   1 +
>  libpoke/ios.c                |   9 +
>  libpoke/libpoke.h            |   1 +
>  libpoke/std.pk               |   6 +
>  po/POTFILES.in               |   1 +
>  poke/pk-cmd-ios.c            |  55 +++++
>  poke/pk-cmd.c                |   6 +
>  poke/pk-help.pk              |  22 ++
>  testsuite/Makefile.am        |   2 +
>  testsuite/lib/poke-dg.exp    |   5 +
>  testsuite/poke.cmd/mmap-1.pk |   8 +
>  testsuite/poke.cmd/mmap-2.pk |   8 +
>  16 files changed, 634 insertions(+)
>  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/configure.ac b/configure.ac
> index f8675239..ffcc4c46 100644
> --- a/configure.ac
> +++ b/configure.ac
> @@ -196,6 +196,11 @@ else
>  fi
>  AM_CONDITIONAL([NBD], [test "x$libnbd_enabled" = "xyes"])
>  
> +dnl Check for mmap
> +AC_FUNC_MMAP
> +
> +AM_CONDITIONAL([HAVE_MMAP], [test "x$ac_cv_func_mmap_fixed_mapped" = "xyes"])
> +
>  dnl Used in Makefile.am.  See the note there.
>  WITH_JITTER=$with_jitter
>  AC_SUBST([WITH_JITTER])
> diff --git a/doc/poke.texi b/doc/poke.texi
> index 1c75d91c..0766d29e 100644
> --- a/doc/poke.texi
> +++ b/doc/poke.texi
> @@ -209,6 +209,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.
> @@ -8820,6 +8821,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.
> @@ -8932,6 +8934,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
> +

It would be good if the documentation would explain why a separated mmap
IOS is necessary to access these files, and in which cases mmap shall be
used rather than a file IOS.

>  @node nbd command
>  @section @code{.nbd}
>  @cindex @code{.nbd}
> diff --git a/libpoke/Makefile.am b/libpoke/Makefile.am
> index 841ecab6..85e76cf1 100644
> --- a/libpoke/Makefile.am
> +++ b/libpoke/Makefile.am
> @@ -66,6 +66,10 @@ libpoke_la_SOURCES = libpoke.h libpoke.c \
>  
>  libpoke_la_SOURCES += ../common/pk-utils.c ../common/pk-utils.h
>  
> +if HAVE_MMAP
> +libpoke_la_SOURCES += ios-dev-mmap.c
> +endif HAVE_MMAP
> +
>  if NBD
>  libpoke_la_SOURCES += ios-dev-nbd.c
>  endif NBD
> diff --git a/libpoke/ios-dev-mmap.c b/libpoke/ios-dev-mmap.c
> new file mode 100644
> index 00000000..a5d0938f
> --- /dev/null
> +++ b/libpoke/ios-dev-mmap.c
> @@ -0,0 +1,459 @@
> +/* ios-dev_map.c - Memory mapped devices.  */

s/_/-/.

> +
> +/* 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())

Please use space between the name of the function and the open
parenthesis.

Also, please import the getpagesize gnulib module.  To do so, just add
getpagesize to libpoke_modules in bootstrap.conf and then re-run
./bootstrap.

> +    {
> +      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;
> +    }
> +
> +  /* should never be the case that returned address is not page aligned as 
> mmap
> +     fails if dev_map->base is not aligned.
> +     But we double check because pread and pwrite rely on this alignment */
> +  if ((unsigned long)dev_map->addr & ((unsigned long)getpagesize() - 1))

Ditto about the missing white space.

> +    {
> +      pk_printf ("Alignment issue treated as error in mmap of %s addr: 
> 0x%x\n",
> +                 dev_map->filename, dev_map->addr);
> +      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 = sizeof (void*);
> +  uint8_t *m = buf;
> +
> +  if (offset > dev_map->size || count > dev_map->size - offset)
> +    return IOD_EOF;
> +
> +  /* copy unaligned bytes
> +     dev_mmap->addr is always page aligned because of mmap */
> +  while (count && offset % align)
> +    {
> +      *m = *(const volatile uint8_t*)(dev_map->addr + offset);
> +      count--;
> +      offset++;
> +      m++;
> +    }
> +
> +  /* copy with the address bus size */
> +  while (count >= align)
> +    {
> +      if (align == 4)
> +        {
> +          *(uint32_t*)m = *(const volatile uint32_t*)(dev_map->addr + 
> offset);
> +        }
> +      else if (align == 8)
> +        {
> +          *(uint64_t*)m = *(const volatile uint64_t*)(dev_map->addr + 
> offset);
> +        }
> +      else
> +        break;
> +      count -= align;
> +      offset += align;
> +      m += align;
> +    }
> +
> +  /* copy remaining unaligned bytes */
> +  while (count)
> +    {
> +      *m = *(const volatile uint8_t*)(dev_map->addr + offset);
> +      count--;
> +      offset++;
> +      m++;
> +    }
> +
> +  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 = sizeof (void*);
> +  const uint8_t *m = buf;
> +
> +  if (offset > dev_map->size || count > dev_map->size - offset)
> +    return IOD_EOF;
> +
> +  /* copy unaligned bytes
> +     dev_mmap->addr is always page aligned because of mmap */
> +  while (count && offset % align)
> +    {
> +      *(volatile uint8_t*)(dev_map->addr + offset) = *(const uint8_t*)m;
> +      count--;
> +      offset++;
> +      m++;
> +    }
> +
> +  /* copy with the address bus size */
> +  while (count >= align)
> +    {
> +      if (align == 4)
> +        {
> +          *(volatile uint32_t*)(dev_map->addr + offset) = *(const 
> uint32_t*)m;
> +        }
> +      else if (align == 8)
> +        {
> +          *(volatile uint64_t*)(dev_map->addr + offset) = *(const 
> uint64_t*)m;
> +        }
> +      else
> +        break;
> +      count -= align;
> +      offset += align;
> +      m += align;
> +    }
> +
> +  /* copy remaining unaligned bytes */
> +  while (count)
> +    {
> +      *(volatile uint8_t*)(dev_map->addr + offset) = *(const uint8_t*)m;
> +      count--;
> +      offset++;
> +      m++;
> +    }
> +
> +  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 IOD_ERROR;
> +        }
> +    }
> +
> +  return IOD_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 95a30e9f..14a6b515 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 a88ae509..335c1e6d 100644
> --- a/libpoke/ios.c
> +++ b/libpoke/ios.c
> @@ -103,6 +103,9 @@ 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 */
> +#ifdef HAVE_MMAP
> +extern struct ios_dev_if ios_dev_mmap; /* ios-dev-mmap.c */
> +#endif
>  
>  enum
>  {
> @@ -112,6 +115,7 @@ enum
>    IOS_DEV_NBD,
>    IOS_DEV_PROC,
>    IOS_DEV_SUB,
> +  IOS_DEV_MMAP,
>    IOS_DEV_FILE, /* File must be last */
>  };
>  
> @@ -131,6 +135,11 @@ static const struct ios_dev_if *ios_dev_ifs[] =
>      [IOS_DEV_PROC] = NULL,
>  #endif
>      [IOS_DEV_SUB] = &ios_dev_sub,
> +#ifdef HAVE_MMAP
> +    [IOS_DEV_MMAP] = &ios_dev_mmap,
> +#else
> +    [IOS_DEV_MMAP] = NULL,
> +#endif
>      [IOS_DEV_FILE] = &ios_dev_file, /* File must be last */
>    };
>  
> diff --git a/libpoke/libpoke.h b/libpoke/libpoke.h
> index 7c592f9d..baee3b91 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 48b2fa4c..e77c2c26 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>:

To follow existing style, please break the line after the first `,' and
then align the rest.

> +{
> +  return open (format ("mmap://%u64d/%u64d/%s", base/#B, size/#B, path));
> +}
> +
>  /*** Miscellanea.  */
>  
>  var NULL = 0#B;
> diff --git a/po/POTFILES.in b/po/POTFILES.in
> index dcac9788..785d1597 100644
> --- a/po/POTFILES.in
> +++ b/po/POTFILES.in
> @@ -4,6 +4,7 @@ libpoke/ios.c
>  libpoke/ios-dev-file.c
>  libpoke/ios-dev.h
>  libpoke/ios-dev-mem.c
> +libpoke/ios-dev-mmap.c
>  libpoke/ios-dev-nbd.c
>  libpoke/ios.h
>  libpoke/pkl-anal.c
> diff --git a/poke/pk-cmd-ios.c b/poke/pk-cmd-ios.c
> index 7e47ed09..c8666f56 100644
> --- a/poke/pk-cmd-ios.c
> +++ b/poke/pk-cmd-ios.c
> @@ -576,6 +576,55 @@ pk_cmd_nbd (int argc, struct pk_cmd_arg argv[], uint64_t 
> uflags)
>  }
>  #endif /* HAVE_LIBNBD */
>  
> +#ifdef HAVE_MMAP
> +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;
> +}
> +#endif /* HAVE_MMAP */
> +
>  const struct pk_cmd ios_cmd =
>    {"ios", "?s", "", 0, NULL, NULL, pk_cmd_ios, ".ios IOS", 
> poke_completion_function};
>  
> @@ -598,6 +647,12 @@ const struct pk_cmd nbd_cmd =
>    {"nbd", "s", "", 0, NULL, NULL, pk_cmd_nbd, ".nbd URI", NULL};
>  #endif
>  
> +#ifdef HAVE_MMAP
> +const struct pk_cmd mmap_cmd =
> +  {"mmap", "s,i,i", "", 0, NULL, NULL, pk_cmd_mmap, ".mmap FILENAME, BASE, 
> SIZE",
> +   NULL};

No rl_filename_completion_function for the mmap arguments?

> +#endif
> +
>  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 40761ead..76dd4cf3 100644
> --- a/poke/pk-cmd.c
> +++ b/poke/pk-cmd.c
> @@ -48,6 +48,9 @@ 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
> +#ifdef HAVE_MMAP
> +extern const struct pk_cmd mmap_cmd; /* pk-cmd-mmap.c */
> +#endif
>  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 */
> @@ -90,6 +93,9 @@ static const struct pk_cmd *dot_cmds[] =
>      &mem_cmd,
>  #ifdef HAVE_LIBNBD
>      &nbd_cmd,
> +#endif
> +#ifdef HAVE_MMAP
> +    &mmap_cmd,
>  #endif
>      &null_cmd
>    };
> diff --git a/poke/pk-help.pk b/poke/pk-help.pk
> index e8c489bb..e86e9fef 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 af858984..dc663ab4 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/lib/poke-dg.exp b/testsuite/lib/poke-dg.exp
> index 5c4bc0b2..b8ece63b 100644
> --- a/testsuite/lib/poke-dg.exp
> +++ b/testsuite/lib/poke-dg.exp
> @@ -71,6 +71,11 @@ proc dg-require { args } {
>          # Mark the test as unsupported
>          set do-what [list [lindex do-what 0] N P]
>      }
> +    if {[lindex $args 1] == "memzero" \
> +            && ! [file exists "/dev/zero"]} {
> +        # Mark the test as unsupported
> +        set do-what [list [lindex do-what 0] N P]
> +    }
>      if {[lindex $args 1] == "nbd" \
>              && $::env(NBDKIT) == "no"} {
>          # Mark the test as unsupported
> diff --git a/testsuite/poke.cmd/mmap-1.pk b/testsuite/poke.cmd/mmap-1.pk
> new file mode 100644
> index 00000000..b61f60d3
> --- /dev/null
> +++ b/testsuite/poke.cmd/mmap-1.pk
> @@ -0,0 +1,8 @@
> +/* { dg-do run } */
> +/* { dg-require memzero } */
> +
> +/* 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" } */



reply via email to

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