summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorUwe Kleine-König <ukleinek@users.noreply.github.com>2018-03-16 11:44:31 +0100
committerGitHub <noreply@github.com>2018-03-16 11:44:31 +0100
commit1ddbb8ef36c2f148c5579ab8c31b35d0eb951006 (patch)
tree8067d359c44e10fb7fcdd0e42e6fcc3de590228c
parenta9e244d4da0f1153381b9410b2c7eada6d6ef52c (diff)
parent433635f857a25ed35e7b3ad8d172a297c65304c1 (diff)
downloadmemtool-1ddbb8ef36c2f148c5579ab8c31b35d0eb951006.tar.gz
memtool-1ddbb8ef36c2f148c5579ab8c31b35d0eb951006.tar.xz
Merge pull request #2 from pengutronix/ukl/mdio
Teach memtool to access mdio devices
-rw-r--r--.gitignore3
-rw-r--r--Makefile.am6
-rw-r--r--acc_mdio.c186
-rw-r--r--acc_mmap.c213
-rw-r--r--configure.ac23
-rw-r--r--fileaccess.c57
-rw-r--r--fileaccess.h21
-rw-r--r--fileaccpriv.h24
-rw-r--r--memtool.116
-rw-r--r--memtool.c200
10 files changed, 646 insertions, 103 deletions
diff --git a/.gitignore b/.gitignore
index e8b677b..e51fe51 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,3 +1,5 @@
+/acc_mdio.o
+/acc_mmap.o
/aclocal.m4
/autom4te.cache
/compile
@@ -6,6 +8,7 @@
/configure
/depcomp
/.deps
+/fileaccess.o
/install-sh
/Makefile
/Makefile.in
diff --git a/Makefile.am b/Makefile.am
index 3786362..a32517f 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -2,7 +2,11 @@ EXTRA_DIST = README.devel
bin_PROGRAMS = memtool
-memtool_SOURCES = memtool.c
+noinst_HEADERS = fileaccess.h fileaccpriv.h
+memtool_SOURCES = memtool.c fileaccess.c acc_mmap.c
+if MDIO
+memtool_SOURCES += acc_mdio.c
+endif
dist_man_MANS = memtool.1
diff --git a/acc_mdio.c b/acc_mdio.c
new file mode 100644
index 0000000..23876c7
--- /dev/null
+++ b/acc_mdio.c
@@ -0,0 +1,186 @@
+/*
+ * Copyright (C) 2018 Pengutronix, Uwe Kleine-König <oss-tools@pengutronix.de>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2, as published by the Free Software Foundation.
+ *
+ * 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 <assert.h>
+#include <errno.h>
+#include <stdio.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/ioctl.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <unistd.h>
+
+#include <linux/if.h>
+#include <linux/mii.h>
+#include <linux/sockios.h>
+
+#include "fileaccpriv.h"
+
+#define container_of(ptr, type, member) \
+ (type *)((char *)(ptr) - (char *) &((type *)0)->member)
+
+struct memtool_mdio_fd {
+ struct memtool_fd mfd;
+ int fd;
+ uint16_t phy_id;
+ char ifrn_name[IFNAMSIZ];
+};
+
+static ssize_t mdio_read(struct memtool_fd *handle, off_t offset,
+ void *buf, size_t nbytes, int width)
+{
+ struct memtool_mdio_fd *mdio_fd =
+ container_of(handle, struct memtool_mdio_fd, mfd);
+ struct ifreq ifr;
+ struct mii_ioctl_data *mii = (void *)&ifr.ifr_data;
+ size_t i = 0;
+ int ret;
+
+ if (width != 2) {
+ fprintf(stderr,
+ "mdio can only be accessed with memory width 2\n");
+ return -EINVAL;
+ }
+
+ assert((nbytes & 1) == 0);
+
+ memset(&ifr, 0, sizeof(ifr));
+ strcpy(ifr.ifr_name, mdio_fd->ifrn_name);
+
+ mii->phy_id = mdio_fd->phy_id;
+
+ while (2 * i < nbytes) {
+ mii->reg_num = offset / 2 + i;
+
+ ret = ioctl(mdio_fd->fd, SIOCGMIIREG, &ifr);
+ if (ret < 0) {
+ perror("Failure to read register");
+ return -1;
+ }
+
+ ((uint16_t *)buf)[i] = mii->val_out;
+ ++i;
+ }
+
+ return 2 * i;
+}
+
+static ssize_t mdio_write(struct memtool_fd *handle, off_t offset,
+ const void *buf, size_t nbytes, int width)
+{
+ struct memtool_mdio_fd *mdio_fd =
+ container_of(handle, struct memtool_mdio_fd, mfd);
+ struct ifreq ifr;
+ struct mii_ioctl_data *mii = (void *)&ifr.ifr_data;
+ size_t i = 0;
+ int ret;
+
+ if (width != 2) {
+ fprintf(stderr,
+ "mdio can only be accessed with memory width 2\n");
+ return -EINVAL;
+ }
+
+ assert((nbytes & 1) == 0);
+
+ memset(&ifr, 0, sizeof(ifr));
+ strcpy(ifr.ifr_name, mdio_fd->ifrn_name);
+
+ mii->phy_id = mdio_fd->phy_id;
+
+ while (2 * i < nbytes) {
+ mii->reg_num = offset / 2 + i;
+ mii->val_in = ((uint16_t *)buf)[i];
+
+ ret = ioctl(mdio_fd->fd, SIOCSMIIREG, &ifr);
+ if (ret < 0) {
+ perror("Failure to write register");
+ return -1;
+ }
+
+ ++i;
+ }
+
+ return 2 * i;
+}
+
+static int mdio_close(struct memtool_fd *handle)
+{
+ struct memtool_mdio_fd *mdio_fd =
+ container_of(handle, struct memtool_mdio_fd, mfd);
+ int ret;
+
+ ret = close(mdio_fd->fd);
+
+ free(mdio_fd);
+
+ return ret;
+}
+
+struct memtool_fd *mdio_open(const char *spec, int flags)
+{
+ struct memtool_mdio_fd *mdio_fd;
+ char *delim;
+ char *endp;
+ long int val;
+
+ mdio_fd = malloc(sizeof(*mdio_fd));
+ if (!mdio_fd) {
+ fprintf(stderr, "Failure to allocate mdio_fd\n");
+ return NULL;
+ }
+
+ mdio_fd->mfd.read = mdio_read;
+ mdio_fd->mfd.write = mdio_write;
+ mdio_fd->mfd.close = mdio_close;
+
+ mdio_fd->fd = socket(AF_INET, SOCK_DGRAM, 0);
+ if (mdio_fd->fd < 0) {
+ perror("socket");
+ goto err_socket;
+ }
+
+ delim = strrchr(spec, '.');
+ if (!delim) {
+ fprintf(stderr, "Failed to parse phy specifier, no \".\"\n");
+ goto err_parse;
+ }
+
+ if (delim - spec >= sizeof(mdio_fd->ifrn_name)) {
+ fprintf(stderr, "device string too long\n");
+ goto err_parse;
+ }
+
+ memcpy(mdio_fd->ifrn_name, spec, delim - spec);
+ mdio_fd->ifrn_name[delim - spec] = '\0';
+
+ val = strtol(delim + 1, &endp, 0);
+ if (*endp != '\0') {
+ fprintf(stderr, "failed to parse phy_id\n");
+ goto err_parse;
+ }
+
+ if (val < 0 || val >= (1 << 16)) {
+ fprintf(stderr, "phy_id out of range\n");
+err_parse:
+ close(mdio_fd->fd);
+err_socket:
+ free(mdio_fd);
+ return NULL;
+ }
+ mdio_fd->phy_id = val;
+
+ return &mdio_fd->mfd;
+}
diff --git a/acc_mmap.c b/acc_mmap.c
new file mode 100644
index 0000000..2b91cdc
--- /dev/null
+++ b/acc_mmap.c
@@ -0,0 +1,213 @@
+/*
+ * Copyright (C) 2018 Pengutronix, Uwe Kleine-König <oss-tools@pengutronix.de>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2, as published by the Free Software Foundation.
+ *
+ * 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 <assert.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/stat.h>
+#include <sys/mman.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+#include "fileaccpriv.h"
+
+#define container_of(ptr, type, member) \
+ (type *)((char *)(ptr) - (char *) &((type *)0)->member)
+
+static off_t mmap_pagesize(void) __attribute__((const));
+static off_t mmap_pagesize(void)
+{
+ static off_t pagesize;
+
+ if (pagesize == 0)
+ pagesize = sysconf(_SC_PAGE_SIZE);
+
+ if (pagesize == 0)
+ pagesize = 4096;
+
+ return pagesize;
+}
+
+struct memtool_mmap_fd {
+ struct memtool_fd mfd;
+ struct stat s;
+ int fd;
+};
+
+static ssize_t mmap_read(struct memtool_fd *handle, off_t offset,
+ void *buf, size_t nbytes, int width)
+{
+ struct memtool_mmap_fd *mmap_fd =
+ container_of(handle, struct memtool_mmap_fd, mfd);
+ struct stat *s = &mmap_fd->s;
+ off_t map_start, map_off;
+ void *map;
+ size_t i = 0;
+ int ret;
+
+ if (S_ISREG(s->st_mode)) {
+ if (s->st_size <= offset) {
+ errno = EINVAL;
+ perror("File to small");
+ return -1;
+ }
+
+ if (s->st_size < offset + nbytes)
+ /* truncating */
+ nbytes = s->st_size - offset;
+ }
+
+ map_start = offset & ~(mmap_pagesize() - 1);
+ map_off = offset - map_start;
+
+ map = mmap(NULL, nbytes + map_off, PROT_READ,
+ MAP_SHARED, mmap_fd->fd, map_start);
+ if (map == MAP_FAILED) {
+ perror("mmap");
+ return -1;
+ }
+
+ while (i * width + width <= nbytes) {
+ switch (width) {
+ case 1:
+ ((uint8_t *)buf)[i] = ((uint8_t *)(map + map_off))[i];
+ break;
+ case 2:
+ ((uint16_t *)buf)[i] = ((uint16_t *)(map + map_off))[i];
+ break;
+ case 4:
+ ((uint32_t *)buf)[i] = ((uint32_t *)(map + map_off))[i];
+ break;
+ case 8:
+ ((uint64_t *)buf)[i] = ((uint64_t *)(map + map_off))[i];
+ break;
+ }
+ ++i;
+ }
+
+ ret = munmap(map, nbytes + map_off);
+ if (ret < 0) {
+ perror("munmap");
+ return -1;
+ }
+
+ return i * width;
+}
+
+static ssize_t mmap_write(struct memtool_fd *handle, off_t offset,
+ const void *buf, size_t nbytes, int width)
+{
+ struct memtool_mmap_fd *mmap_fd =
+ container_of(handle, struct memtool_mmap_fd, mfd);
+ struct stat *s = &mmap_fd->s;
+ off_t map_start, map_off;
+ void *map;
+ size_t i = 0;
+ int ret;
+
+ if (S_ISREG(s->st_mode) && s->st_size < offset + nbytes) {
+ ret = posix_fallocate(mmap_fd->fd, offset, nbytes);
+ if (ret) {
+ errno = ret;
+ perror("fallocate");
+ return -1;
+ }
+ s->st_size = offset + nbytes;
+ }
+
+ map_start = offset & ~(mmap_pagesize() - 1);
+ map_off = offset - map_start;
+
+ map = mmap(NULL, nbytes + map_off, PROT_WRITE,
+ MAP_SHARED, mmap_fd->fd, map_start);
+ if (map == MAP_FAILED) {
+ perror("mmap");
+ return -1;
+ }
+
+ while (i * width + width <= nbytes) {
+ switch (width) {
+ case 1:
+ ((uint8_t *)(map + map_off))[i] = ((uint8_t *)buf)[i];
+ break;
+ case 2:
+ ((uint16_t *)(map + map_off))[i] = ((uint16_t *)buf)[i];
+ break;
+ case 4:
+ ((uint32_t *)(map + map_off))[i] = ((uint32_t *)buf)[i];
+ break;
+ case 8:
+ ((uint64_t *)(map + map_off))[i] = ((uint64_t *)buf)[i];
+ break;
+ }
+ ++i;
+ }
+
+ ret = munmap(map, nbytes + map_off);
+ if (ret < 0) {
+ perror("munmap");
+ return -1;
+ }
+
+ return i * width;
+}
+
+static int mmap_close(struct memtool_fd *handle)
+{
+ struct memtool_mmap_fd *mmap_fd =
+ container_of(handle, struct memtool_mmap_fd, mfd);
+ int ret;
+
+ ret = close(mmap_fd->fd);
+
+ free(mmap_fd);
+
+ return ret;
+}
+
+struct memtool_fd *mmap_open(const char *spec, int flags)
+{
+ struct memtool_mmap_fd *mmap_fd;
+ int ret;
+
+ mmap_fd = malloc(sizeof(*mmap_fd));
+ if (!mmap_fd) {
+ fprintf(stderr, "Failure to allocate mmap_fd\n");
+ return NULL;
+ }
+
+ mmap_fd->mfd.read = mmap_read;
+ mmap_fd->mfd.write = mmap_write;
+ mmap_fd->mfd.close = mmap_close;
+
+ mmap_fd->fd = open(spec, flags, S_IRUSR | S_IWUSR);
+ if (mmap_fd->fd < 0) {
+ perror("open");
+ free(mmap_fd);
+ return NULL;
+ }
+
+ ret = fstat(mmap_fd->fd, &mmap_fd->s);
+ if (ret) {
+ perror("fstat");
+ close(mmap_fd->fd);
+ free(mmap_fd);
+ return NULL;
+ }
+
+ return &mmap_fd->mfd;
+}
diff --git a/configure.ac b/configure.ac
index 55273a2..dca7faa 100644
--- a/configure.ac
+++ b/configure.ac
@@ -8,5 +8,28 @@ AC_PROG_MAKE_SET
AC_SYS_LARGEFILE
+AC_ARG_ENABLE([mdio], [AS_HELP_STRING([--enable-mdio], [enable mdio access method @<:@default=check@:>@])],, [enable_mdio=check])
+
+AS_IF([test "x$enable_mdio" != "xno"],
+ [AC_CHECK_HEADERS([sys/socket.h linux/if.h linux/mii.h linux/sockios.h],,
+ [AS_IF([test "x$enable_mdio" != "xyes"], [enable_mdio=no; break], [AC_MSG_ERROR([mdio depends on Linux mdio headers])])],
+ dnl some versions of linux/if.h are not self-contained and need struct sockaddr
+ dnl see https://git.kernel.org/linus/2618be7dccf8739b89e1906b64bd8d551af351e6
+ [[#ifdef HAVE_SYS_SOCKET_H
+ # include <sys/socket.h>
+ #endif
+ ]])
+ AS_IF([test "x$enable_mdio" = "xcheck"], [enable_mdio=yes])
+ ])
+
+AC_MSG_CHECKING([for mdio support])
+AS_IF([test "x$enable_mdio" = "xyes"],
+ [AC_DEFINE([USE_MDIO], [1], [Define if the mdio access method should be built-in])
+ AC_MSG_RESULT([yes])
+ ], [AC_MSG_RESULT([no])])
+
+AM_CONDITIONAL([MDIO], [test "x$enable_mdio" = "xyes"])
+
AC_CONFIG_FILES([Makefile])
+
AC_OUTPUT
diff --git a/fileaccess.c b/fileaccess.c
new file mode 100644
index 0000000..4fa89c2
--- /dev/null
+++ b/fileaccess.c
@@ -0,0 +1,57 @@
+/*
+ * Copyright (C) 2018 Pengutronix, Uwe Kleine-König <oss-tools@pengutronix.de>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2, as published by the Free Software Foundation.
+ *
+ * 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 <string.h>
+#include <stdio.h>
+
+#include "fileaccess.h"
+#include "fileaccpriv.h"
+
+void *memtool_open(const char *spec, int flags)
+{
+ if (!strncmp(spec, "mmap:", 5)) {
+ return mmap_open(spec + 5, flags);
+ } else if (!strncmp(spec, "mdio:", 5)) {
+#ifdef USE_MDIO
+ return mdio_open(spec + 5, flags);
+#else
+ fprintf(stderr, "mdio support not compiled in\n");
+ return NULL;
+#endif
+ } else {
+ return mmap_open(spec, flags);
+ }
+}
+
+ssize_t memtool_read(void *handle,
+ off_t offset, void *buf, size_t nbytes, int width)
+{
+ struct memtool_fd *mfd = handle;
+
+ return mfd->read(mfd, offset, buf, nbytes, width);
+}
+
+ssize_t memtool_write(void *handle,
+ off_t offset, const void *buf, size_t nbytes, int width)
+{
+ struct memtool_fd *mfd = handle;
+
+ return mfd->write(mfd, offset, buf, nbytes, width);
+}
+
+int memtool_close(void *handle)
+{
+ struct memtool_fd *mfd = handle;
+
+ return mfd->close(mfd);
+}
diff --git a/fileaccess.h b/fileaccess.h
new file mode 100644
index 0000000..ba237d0
--- /dev/null
+++ b/fileaccess.h
@@ -0,0 +1,21 @@
+/*
+ * Copyright (C) 2018 Pengutronix, Uwe Kleine-König <oss-tools@pengutronix.de>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2, as published by the Free Software Foundation.
+ *
+ * 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 <sys/types.h>
+
+void *memtool_open(const char *spec, int flags);
+ssize_t memtool_read(void *handle, off_t offset,
+ void *buf, size_t nbytes, int width);
+ssize_t memtool_write(void *handle, off_t offset,
+ const void *buf, size_t nbytes, int width);
+int memtool_close(void *handle);
diff --git a/fileaccpriv.h b/fileaccpriv.h
new file mode 100644
index 0000000..25fc4d6
--- /dev/null
+++ b/fileaccpriv.h
@@ -0,0 +1,24 @@
+/*
+ * Copyright (C) 2018 Pengutronix, Uwe Kleine-König <oss-tools@pengutronix.de>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2, as published by the Free Software Foundation.
+ *
+ * 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 <sys/types.h>
+
+struct memtool_fd {
+ ssize_t (*read)(struct memtool_fd *handle, off_t offset,
+ void *buf, size_t nbytes, int width);
+ ssize_t (*write)(struct memtool_fd *handle, off_t offset,
+ const void *buf, size_t nbytes, int width);
+ int (*close)(struct memtool_fd *handle);
+};
+
+struct memtool_fd *mdio_open(const char *spec, int flags);
+struct memtool_fd *mmap_open(const char *spec, int flags);
diff --git a/memtool.1 b/memtool.1
index 0bc0ec3..40f4b11 100644
--- a/memtool.1
+++ b/memtool.1
@@ -29,6 +29,22 @@ to write to memory/a file; and
.B md
to read from memory/a file.
+Usually memtool operates on files (regular or devices) using mmap(2). If
+.I filename
+is of the form
+.RI mdio: ethname . id
+with
+.I ethname
+being the name of an ethernet device and
+.I id
+being an MDIO address, the phy with address
+.I id
+on the MDIO bus related to the ethernet device
+.I ethname
+is accessed instead. To prevent ambiguities when using the mmap access method, use
+.RI mmap: filename
+as parameter.
+
Note that on some machines there are alignment restrictions that forbid for
example to read a word from an address that is not word aligned. memtool
doesn't try to be smart here but simply tries what is requested by the caller.
diff --git a/memtool.c b/memtool.c
index 16da84d..95fcb6b 100644
--- a/memtool.c
+++ b/memtool.c
@@ -11,7 +11,9 @@
* GNU General Public License for more details.
*/
+#include <assert.h>
#include <libgen.h>
+#include <stdint.h>
#include <stdio.h>
#include <sys/mman.h>
#include <sys/types.h>
@@ -26,6 +28,8 @@
#include <string.h>
#include <inttypes.h>
+#include "fileaccess.h"
+
#define DISP_LINE_LEN 16
/*
@@ -194,72 +198,6 @@ static int memory_display(const void *addr, off_t offs,
return 0;
}
-static int memfd;
-
-static void *memmap(const char *file, off_t addr, size_t *size, int readonly)
-{
- off_t mmap_start;
- size_t ofs;
- void *mem;
- long pagesize = sysconf(_SC_PAGE_SIZE);
- struct stat s;
- int ret;
-
- if (pagesize < 0)
- pagesize = 4096;
-
- memfd = open(file, readonly ? O_RDONLY : (O_RDWR | O_CREAT),
- S_IRUSR | S_IWUSR);
- if (memfd < 0) {
- perror("open");
- return NULL;
- }
-
- ret = fstat(memfd, &s);
- if (ret) {
- perror("fstat");
- goto out;
- }
-
- if (S_ISREG(s.st_mode)) {
- if (readonly) {
- if (s.st_size <= addr) {
- errno = EINVAL;
- perror("File to small");
- goto out;
- }
-
- if (s.st_size < addr + *size)
- /* truncating */
- *size = s.st_size - addr;
-
- } else if (s.st_size < addr + *size) {
- int ret = posix_fallocate(memfd, addr, *size);
- if (ret) {
- errno = ret;
- perror("Failed to fallocate");
- goto out;
- }
- }
- }
-
- mmap_start = addr & ~((off_t)pagesize - 1);
- ofs = addr - mmap_start;
-
- mem = mmap(NULL, *size + ofs, PROT_READ | (readonly ? 0 : PROT_WRITE),
- MAP_SHARED, memfd, mmap_start);
- if (mem == MAP_FAILED) {
- perror("mmap");
- goto out;
- }
-
- return mem + ofs;
-out:
- close(memfd);
-
- return NULL;
-}
-
static void usage_md(void)
{
printf(
@@ -289,9 +227,10 @@ static int cmd_memory_display(int argc, char **argv)
{
int opt;
int width = 4;
- size_t size = 0x100;
+ size_t bufsize, size = 0x100;
+ char *buf;
+ void *handle;
off_t start = 0x0;
- void *mem;
char *file = "/dev/mem";
int swap = 0;
@@ -330,13 +269,47 @@ static int cmd_memory_display(int argc, char **argv)
size = 0x100;
}
- mem = memmap(file, start, &size, 1);
- if (!mem)
+ if (size & (width - 1)) {
+ size &= ~(width - 1);
+ fprintf(stderr, "warning: skipping truncated read, size=%zu\n",
+ size);
+ }
+
+ if (!size)
+ return EXIT_SUCCESS;
+
+ bufsize = size;
+ if (bufsize > 4096)
+ bufsize = 4096;
+
+ buf = malloc(bufsize);
+ if (!buf) {
+ fprintf(stderr, "could not allocate memory\n");
return EXIT_FAILURE;
+ }
+
+ handle = memtool_open(file, O_RDONLY);
+ if (!handle)
+ return EXIT_FAILURE;
+
+ while (size) {
+ int ret;
+
+ if (size < bufsize)
+ bufsize = size;
+
+ ret = memtool_read(handle, start, buf, bufsize, width);
+ if (ret < 0)
+ return EXIT_FAILURE;
+
+ assert(ret == bufsize);
+ memory_display(buf, start, bufsize, width, swap);
- memory_display(mem, start, size, width, swap);
+ start += bufsize;
+ size -= bufsize;
+ }
- close(memfd);
+ memtool_close(handle);
return EXIT_SUCCESS;
}
@@ -362,10 +335,12 @@ static void usage_mw(void)
static int cmd_memory_write(int argc, char *argv[])
{
off_t adr;
- size_t size;
+ size_t bufsize, size;
+ char *buf;
+ void *handle;
int width = 4;
int opt;
- void *mem;
+ int i, ret;
char *file = "/dev/mem";
while ((opt = getopt(argc, argv, "bwlqd:h")) != -1) {
@@ -399,41 +374,62 @@ static int cmd_memory_write(int argc, char *argv[])
adr = strtoull_suffix(argv[optind++], NULL, 0);
size = (argc - optind) * width;
- mem = memmap(file, adr, &size, 0);
- if (!mem)
+ if (!size)
+ return EXIT_SUCCESS;
+
+ bufsize = size;
+ if (bufsize > 4096)
+ bufsize = 4096;
+
+ buf = malloc(bufsize);
+ if (!buf) {
+ fprintf(stderr, "could not allocate memory\n");
+ return EXIT_FAILURE;
+ }
+
+ handle = memtool_open(file, O_RDWR | O_CREAT);
+ if (!handle)
return EXIT_FAILURE;
while (optind < argc) {
- uint8_t val8;
- uint16_t val16;
- uint32_t val32;
- uint64_t val64;
-
- switch (width) {
- case 1:
- val8 = strtoul(argv[optind], NULL, 0);
- *(volatile uint8_t *)mem = val8;
- break;
- case 2:
- val16 = strtoul(argv[optind], NULL, 0);
- *(volatile uint16_t *)mem = val16;
- break;
- case 4:
- val32 = strtoul(argv[optind], NULL, 0);
- *(volatile uint32_t *)mem = val32;
- break;
- case 8:
- val64 = strtoull(argv[optind], NULL, 0);
- *(volatile uint64_t *)mem = val64;
- break;
+ i = 0;
+
+ while (optind < argc && i * width < bufsize) {
+ switch (width) {
+ case 1:
+ ((uint8_t *)buf)[i] =
+ strtoull(argv[optind], NULL, 0);
+ break;
+ case 2:
+ ((uint16_t *)buf)[i] =
+ strtoull(argv[optind], NULL, 0);
+ break;
+ case 4:
+ ((uint32_t *)buf)[i] =
+ strtoull(argv[optind], NULL, 0);
+ break;
+ case 8:
+ ((uint64_t *)buf)[i] =
+ strtoull(argv[optind], NULL, 0);
+ break;
+ }
+ ++i;
+ ++optind;
}
- mem += width;
- optind++;
+
+ ret = memtool_write(handle, adr, buf, i * width, width);
+ if (ret < 0)
+ break;
+
+ assert(ret == i * width);
+ adr += i * width;
}
- close(memfd);
- return 0;
+ memtool_close(handle);
+ free(buf);
+
+ return ret < 0 ? EXIT_FAILURE : EXIT_SUCCESS;
}
struct cmd {