Index: uspace/app/tester/ipc/readwrite.c
===================================================================
--- uspace/app/tester/ipc/readwrite.c	(revision d53a5ab03c9908a886b8d7780095b6f74858e51a)
+++ uspace/app/tester/ipc/readwrite.c	(revision d53a5ab03c9908a886b8d7780095b6f74858e51a)
@@ -0,0 +1,126 @@
+/*
+ * Copyright (c) 2023 Jiri Svoboda
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in the
+ *   documentation and/or other materials provided with the distribution.
+ * - The name of the author may not be used to endorse or promote products
+ *   derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <as.h>
+#include <errno.h>
+#include <mem.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <ipc_test.h>
+#include "../tester.h"
+
+enum {
+	rw_buf_size = 1024
+};
+
+static uint8_t rw_buf[rw_buf_size];
+
+const char *test_readwrite(void)
+{
+	ipc_test_t *test = NULL;
+	size_t i;
+	errno_t rc;
+
+	rc = ipc_test_create(&test);
+	if (rc != EOK)
+		return "Error contacting IPC test service.";
+
+	rc = ipc_test_set_rw_buf_size(test, rw_buf_size);
+	if (rc != EOK)
+		return "Error getting read-only area size.";
+
+	/*
+	 * Write all zeroes to remote buffer
+	 */
+	memset(rw_buf, 0x00, rw_buf_size);
+	rc = ipc_test_write(test, rw_buf, rw_buf_size);
+	if (rc != EOK)
+		return "Error writing remote buffer.";
+
+	TPRINTF("Successfully wrote zeroes to remote buffer.\n");
+
+	/*
+	 * Read back contents of remote buffer and verify
+	 */
+
+	/*
+	 * Make sure the contents of local buffer are different from what
+	 * we expect to read.
+	 */
+	memset(rw_buf, 0xff, rw_buf_size);
+	rc = ipc_test_read(test, rw_buf, rw_buf_size);
+	if (rc != EOK)
+		return "Error reading remote buffer.";
+
+	TPRINTF("Successfully read back remote buffer.\n");
+
+	/* Now verify what we have read */
+	for (i = 0; i < rw_buf_size; i++) {
+		if (rw_buf[i] != 0x00)
+			return "Failed verification of read data.";
+	}
+
+	TPRINTF("Read data succeeded verification.\n");
+
+	/*
+	 * Write all binary ones to remote buffer
+	 */
+	memset(rw_buf, 0xff, rw_buf_size);
+	rc = ipc_test_write(test, rw_buf, rw_buf_size);
+	if (rc != EOK)
+		return "Error writing remote buffer.";
+
+	TPRINTF("Successfully wrote binary ones to remote buffer.\n");
+
+	/*
+	 * Read back contents of remote buffer and verify
+	 */
+
+	/*
+	 * Make sure the contents of local buffer are different from what
+	 * we expect to read.
+	 */
+	memset(rw_buf, 0x00, rw_buf_size);
+	rc = ipc_test_read(test, rw_buf, rw_buf_size);
+	if (rc != EOK)
+		return "Error reading remote buffer.";
+
+	TPRINTF("Successfully read back remote buffer.\n");
+
+	/* Now verify what we have read */
+	for (i = 0; i < rw_buf_size; i++) {
+		if (rw_buf[i] != 0xff)
+			return "Failed verification of read data.";
+	}
+
+	TPRINTF("Read data succeeded verification.\n");
+
+	ipc_test_destroy(test);
+	return NULL;
+}
Index: uspace/app/tester/ipc/readwrite.def
===================================================================
--- uspace/app/tester/ipc/readwrite.def	(revision d53a5ab03c9908a886b8d7780095b6f74858e51a)
+++ uspace/app/tester/ipc/readwrite.def	(revision d53a5ab03c9908a886b8d7780095b6f74858e51a)
@@ -0,0 +1,6 @@
+{
+	"readwrite",
+	"IPC read/write test",
+	&test_readwrite,
+	true
+},
Index: uspace/app/tester/meson.build
===================================================================
--- uspace/app/tester/meson.build	(revision 4f6368c9f43c5e184ce86a446688b4311b0d63f1)
+++ uspace/app/tester/meson.build	(revision d53a5ab03c9908a886b8d7780095b6f74858e51a)
@@ -52,4 +52,5 @@
 	'float/float2.c',
 	'vfs/vfs1.c',
+	'ipc/readwrite.c',
 	'ipc/sharein.c',
 	'ipc/starve.c',
Index: uspace/app/tester/tester.c
===================================================================
--- uspace/app/tester/tester.c	(revision 4f6368c9f43c5e184ce86a446688b4311b0d63f1)
+++ uspace/app/tester/tester.c	(revision d53a5ab03c9908a886b8d7780095b6f74858e51a)
@@ -68,4 +68,5 @@
 #include "float/float2.def"
 #include "vfs/vfs1.def"
+#include "ipc/readwrite.def"
 #include "ipc/sharein.def"
 #include "ipc/starve.def"
Index: uspace/app/tester/tester.h
===================================================================
--- uspace/app/tester/tester.h	(revision 4f6368c9f43c5e184ce86a446688b4311b0d63f1)
+++ uspace/app/tester/tester.h	(revision d53a5ab03c9908a886b8d7780095b6f74858e51a)
@@ -99,4 +99,5 @@
 extern const char *test_vfs1(void);
 extern const char *test_ping_pong(void);
+extern const char *test_readwrite(void);
 extern const char *test_sharein(void);
 extern const char *test_starve_ipc(void);
Index: uspace/lib/ipctest/include/ipc/ipc_test.h
===================================================================
--- uspace/lib/ipctest/include/ipc/ipc_test.h	(revision 4f6368c9f43c5e184ce86a446688b4311b0d63f1)
+++ uspace/lib/ipctest/include/ipc/ipc_test.h	(revision d53a5ab03c9908a886b8d7780095b6f74858e51a)
@@ -43,5 +43,8 @@
 	IPC_TEST_GET_RW_AREA_SIZE,
 	IPC_TEST_SHARE_IN_RO,
-	IPC_TEST_SHARE_IN_RW
+	IPC_TEST_SHARE_IN_RW,
+	IPC_TEST_SET_RW_BUF_SIZE,
+	IPC_TEST_READ,
+	IPC_TEST_WRITE
 } ipc_test_request_t;
 
Index: uspace/lib/ipctest/include/ipc_test.h
===================================================================
--- uspace/lib/ipctest/include/ipc_test.h	(revision 4f6368c9f43c5e184ce86a446688b4311b0d63f1)
+++ uspace/lib/ipctest/include/ipc_test.h	(revision d53a5ab03c9908a886b8d7780095b6f74858e51a)
@@ -50,4 +50,7 @@
 extern errno_t ipc_test_share_in_ro(ipc_test_t *, size_t, const void **);
 extern errno_t ipc_test_share_in_rw(ipc_test_t *, size_t, void **);
+extern errno_t ipc_test_set_rw_buf_size(ipc_test_t *, size_t);
+extern errno_t ipc_test_read(ipc_test_t *, void *, size_t);
+extern errno_t ipc_test_write(ipc_test_t *, const void *, size_t);
 
 #endif
Index: uspace/lib/ipctest/src/ipc_test.c
===================================================================
--- uspace/lib/ipctest/src/ipc_test.c	(revision 4f6368c9f43c5e184ce86a446688b4311b0d63f1)
+++ uspace/lib/ipctest/src/ipc_test.c	(revision d53a5ab03c9908a886b8d7780095b6f74858e51a)
@@ -1,4 +1,4 @@
 /*
- * Copyright (c) 2018 Jiri Svoboda
+ * Copyright (c) 2023 Jiri Svoboda
  * All rights reserved.
  *
@@ -221,4 +221,83 @@
 }
 
+/** Set server-side read/write buffer size.
+ *
+ * @param test IPC test service
+ * @param size Requested read/write buffer size
+ * @return EOK on success or an error code
+ */
+errno_t ipc_test_set_rw_buf_size(ipc_test_t *test, size_t size)
+{
+	async_exch_t *exch;
+	errno_t retval;
+
+	exch = async_exchange_begin(test->sess);
+	retval = async_req_1_0(exch, IPC_TEST_SET_RW_BUF_SIZE, size);
+	async_exchange_end(exch);
+
+	if (retval != EOK)
+		return retval;
+
+	return EOK;
+}
+
+/** Test IPC read.
+ *
+ * @param test IPC test service
+ * @param dest Destination buffer
+ * @param size Number of bytes to read / size of destination buffer
+ * @return EOK on success or an error code
+ */
+errno_t ipc_test_read(ipc_test_t *test, void *dest, size_t size)
+{
+	async_exch_t *exch;
+	ipc_call_t answer;
+	aid_t req;
+	errno_t rc;
+
+	exch = async_exchange_begin(test->sess);
+	req = async_send_0(exch, IPC_TEST_READ, &answer);
+
+	rc = async_data_read_start(exch, dest, size);
+	if (rc != EOK) {
+		async_exchange_end(exch);
+		async_forget(req);
+		return rc;
+	}
+
+	async_exchange_end(exch);
+	async_wait_for(req, NULL);
+	return EOK;
+}
+
+/** Test IPC write.
+ *
+ * @param test IPC test service
+ * @param data Source buffer
+ * @param size Number of bytes to write
+ * @return EOK on success or an error code
+ */
+errno_t ipc_test_write(ipc_test_t *test, const void *data, size_t size)
+{
+	async_exch_t *exch;
+	ipc_call_t answer;
+	aid_t req;
+	errno_t rc;
+
+	exch = async_exchange_begin(test->sess);
+	req = async_send_0(exch, IPC_TEST_WRITE, &answer);
+
+	rc = async_data_write_start(exch, data, size);
+	if (rc != EOK) {
+		async_exchange_end(exch);
+		async_forget(req);
+		return rc;
+	}
+
+	async_exchange_end(exch);
+	async_wait_for(req, NULL);
+	return EOK;
+}
+
 /** @}
  */
Index: uspace/srv/test/ipc-test/main.c
===================================================================
--- uspace/srv/test/ipc-test/main.c	(revision 4f6368c9f43c5e184ce86a446688b4311b0d63f1)
+++ uspace/srv/test/ipc-test/main.c	(revision d53a5ab03c9908a886b8d7780095b6f74858e51a)
@@ -48,4 +48,5 @@
 #include <mem.h>
 #include <stdio.h>
+#include <stdlib.h>
 #include <task.h>
 
@@ -53,4 +54,8 @@
 
 static service_id_t svc_id;
+
+enum {
+	max_rw_buf_size = 16384,
+};
 
 /** Object in read-only memory area that will be shared.
@@ -67,4 +72,12 @@
  */
 static char rw_data[] = "Hello, world!";
+
+/** Buffer for reading/writing via read/write messages.
+ *
+ * It is allocated / size is set by IPC_TEST_SET_RW_BUF_SIZE
+ */
+static void *rw_buf;
+/** Read/write buffer size */
+size_t rw_buf_size;
 
 static void ipc_test_get_ro_area_size_srv(ipc_call_t *icall)
@@ -182,4 +195,103 @@
 }
 
+static void ipc_test_set_rw_buf_size_srv(ipc_call_t *icall)
+{
+	size_t size;
+	void *nbuf;
+
+	log_msg(LOG_DEFAULT, LVL_DEBUG, "ipc_test_set_rw_buf_size_srv");
+
+	size = ipc_get_arg1(icall);
+
+	if (size == 0) {
+		async_answer_0(icall, ERANGE);
+		log_msg(LOG_DEFAULT, LVL_ERROR,
+		    "Requested read/write buffer size is zero.");
+		return;
+	}
+
+	if (size > max_rw_buf_size) {
+		async_answer_0(icall, ERANGE);
+		log_msg(LOG_DEFAULT, LVL_ERROR, "Requested read/write buffer "
+		    "size > %u", max_rw_buf_size);
+		return;
+	}
+
+	nbuf = realloc(rw_buf, size);
+	if (nbuf == NULL) {
+		async_answer_0(icall, ENOMEM);
+		log_msg(LOG_DEFAULT, LVL_ERROR, "Out of memory.");
+		return;
+	}
+
+	rw_buf = nbuf;
+	rw_buf_size = size;
+	async_answer_0(icall, EOK);
+}
+
+static void ipc_test_read_srv(ipc_call_t *icall)
+{
+	ipc_call_t call;
+	errno_t rc;
+	size_t size;
+
+	log_msg(LOG_DEFAULT, LVL_DEBUG, "ipc_test_read_srv");
+
+	if (!async_data_read_receive(&call, &size)) {
+		async_answer_0(icall, EREFUSED);
+		log_msg(LOG_DEFAULT, LVL_ERROR, "data_read_receive failed");
+		return;
+	}
+
+	if (size > rw_buf_size) {
+		async_answer_0(&call, EINVAL);
+		async_answer_0(icall, EINVAL);
+		log_msg(LOG_DEFAULT, LVL_ERROR, "Invalid read size.");
+		return;
+	}
+
+	rc = async_data_read_finalize(&call, rw_buf, size);
+	if (rc != EOK) {
+		log_msg(LOG_DEFAULT, LVL_ERROR,
+		    "data_read_finalize failed");
+		async_answer_0(icall, EINVAL);
+		return;
+	}
+
+	async_answer_0(icall, EOK);
+}
+
+static void ipc_test_write_srv(ipc_call_t *icall)
+{
+	ipc_call_t call;
+	errno_t rc;
+	size_t size;
+
+	log_msg(LOG_DEFAULT, LVL_DEBUG, "ipc_test_write_srv");
+
+	if (!async_data_write_receive(&call, &size)) {
+		async_answer_0(icall, EREFUSED);
+		log_msg(LOG_DEFAULT, LVL_ERROR, "data_write_receive failed");
+		return;
+	}
+
+	if (size > rw_buf_size) {
+		async_answer_0(&call, EINVAL);
+		async_answer_0(icall, EINVAL);
+		log_msg(LOG_DEFAULT, LVL_ERROR, "Invalid write size.");
+		return;
+	}
+
+	rc = async_data_write_finalize(&call, rw_buf, size);
+	if (rc != EOK) {
+		log_msg(LOG_DEFAULT, LVL_ERROR,
+		    "data_write_finalize failed");
+		async_answer_0(icall, EINVAL);
+		return;
+	}
+
+	async_answer_0(icall, EOK);
+}
+
 static void ipc_test_connection(ipc_call_t *icall, void *arg)
 {
@@ -211,4 +323,13 @@
 		case IPC_TEST_SHARE_IN_RW:
 			ipc_test_share_in_rw_srv(&call);
+			break;
+		case IPC_TEST_SET_RW_BUF_SIZE:
+			ipc_test_set_rw_buf_size_srv(&call);
+			break;
+		case IPC_TEST_READ:
+			ipc_test_read_srv(&call);
+			break;
+		case IPC_TEST_WRITE:
+			ipc_test_write_srv(&call);
 			break;
 		default:
