xref: /openbmc/hiomapd/test/mbox.c (revision 68a24c9ea5ce11c87fab22a3f4648c7d88c98fee)
14fe996c2SAndrew Jeffery // SPDX-License-Identifier: Apache-2.0
24fe996c2SAndrew Jeffery // Copyright (C) 2018 IBM Corp.
35ab4e3e8SAndrew Jeffery 
45ab4e3e8SAndrew Jeffery #define _GNU_SOURCE /* fallocate */
55ab4e3e8SAndrew Jeffery #include <assert.h>
65ab4e3e8SAndrew Jeffery #include <fcntl.h>
75ab4e3e8SAndrew Jeffery #include <stdint.h>
85ab4e3e8SAndrew Jeffery #include <stdio.h>
95ab4e3e8SAndrew Jeffery #include <stdlib.h>
105ab4e3e8SAndrew Jeffery #include <string.h>
11f1e547c7SEvan Lojewski #include <sys/ioctl.h>
125ab4e3e8SAndrew Jeffery #include <sys/mman.h>
135ab4e3e8SAndrew Jeffery #include <sys/types.h>
145ab4e3e8SAndrew Jeffery #include <sys/stat.h>
155ab4e3e8SAndrew Jeffery #include <unistd.h>
165ab4e3e8SAndrew Jeffery 
17f1e547c7SEvan Lojewski #include "config.h"
1826558dbbSAndrew Jeffery #include "mboxd.h"
19f1e547c7SEvan Lojewski #include "backend.h"
20cd18611eSAndrew Jeffery #include "lpc.h"
21457a6e5fSAndrew Jeffery #include "transport_mbox.h"
22f593b1bdSAndrew Jeffery #include "windows.h"
235ab4e3e8SAndrew Jeffery 
245ab4e3e8SAndrew Jeffery #include "test/mbox.h"
255ab4e3e8SAndrew Jeffery 
265ab4e3e8SAndrew Jeffery #define STEP 16
275ab4e3e8SAndrew Jeffery 
dump_buf(const void * buf,size_t len)28ee7af883SAndrew Jeffery void dump_buf(const void *buf, size_t len)
295ab4e3e8SAndrew Jeffery {
30ee7af883SAndrew Jeffery 	const uint8_t *buf8 = buf;
31*68a24c9eSPatrick Williams 	size_t i;
325ab4e3e8SAndrew Jeffery 
335ab4e3e8SAndrew Jeffery 	for (i = 0; i < len; i += STEP) {
345ab4e3e8SAndrew Jeffery 		int delta;
355ab4e3e8SAndrew Jeffery 		int max;
365ab4e3e8SAndrew Jeffery 		int j;
375ab4e3e8SAndrew Jeffery 
385ab4e3e8SAndrew Jeffery 		delta = len - i;
395ab4e3e8SAndrew Jeffery 		max = delta > STEP ? STEP : delta;
405ab4e3e8SAndrew Jeffery 
41*68a24c9eSPatrick Williams 		printf("0x%08zx:\t", i);
425ab4e3e8SAndrew Jeffery 		for (j = 0; j < max; j++)
43ee7af883SAndrew Jeffery 			printf("0x%02x, ", buf8[i + j]);
445ab4e3e8SAndrew Jeffery 
455ab4e3e8SAndrew Jeffery 		printf("\n");
465ab4e3e8SAndrew Jeffery 	}
475ab4e3e8SAndrew Jeffery 	printf("\n");
485ab4e3e8SAndrew Jeffery }
495ab4e3e8SAndrew Jeffery 
505ab4e3e8SAndrew Jeffery /*
515ab4e3e8SAndrew Jeffery  * Because we are using a file and not a pipe for the mbox file descriptor we
525ab4e3e8SAndrew Jeffery  * need to handle a difference in behaviour. For a given command and response
535ab4e3e8SAndrew Jeffery  * sequence the first 16 bytes of the file are occupied by the mbox command.
545ab4e3e8SAndrew Jeffery  * The response occupies the following 14 bytes for a total of 30 bytes.
555ab4e3e8SAndrew Jeffery  *
565ab4e3e8SAndrew Jeffery  * We also have to ensure we lseek() to reset the file descriptor offset back
575ab4e3e8SAndrew Jeffery  * to the start of the file before dispatching the mbox command.
585ab4e3e8SAndrew Jeffery  */
595ab4e3e8SAndrew Jeffery 
605ab4e3e8SAndrew Jeffery /* Macros for handling the pipe/file discrepancy */
615ab4e3e8SAndrew Jeffery #define RESPONSE_OFFSET	16
625ab4e3e8SAndrew Jeffery #define RESPONSE_SIZE	14
635ab4e3e8SAndrew Jeffery 
mbox_cmp(struct mbox_context * context,const uint8_t * expected,size_t len)645ab4e3e8SAndrew Jeffery int mbox_cmp(struct mbox_context *context, const uint8_t *expected, size_t len)
655ab4e3e8SAndrew Jeffery {
665ab4e3e8SAndrew Jeffery 	struct stat details;
675ab4e3e8SAndrew Jeffery 	uint8_t *map;
685ab4e3e8SAndrew Jeffery 	int rc;
695ab4e3e8SAndrew Jeffery 	int fd;
705ab4e3e8SAndrew Jeffery 
715ab4e3e8SAndrew Jeffery 	fd = context->fds[MBOX_FD].fd;
725ab4e3e8SAndrew Jeffery 	fstat(fd, &details);
735ab4e3e8SAndrew Jeffery 
745ab4e3e8SAndrew Jeffery 	map = mmap(NULL, details.st_size, PROT_READ, MAP_PRIVATE, fd, 0);
7523a48212SAndrew Jeffery 	printf("%s:%d: details.st_size: %ld, RESPONSE_OFFSET + len: %ld\n",
7623a48212SAndrew Jeffery 	       __func__, __LINE__, details.st_size, RESPONSE_OFFSET + len);
775ab4e3e8SAndrew Jeffery 	assert(map != MAP_FAILED);
78*68a24c9eSPatrick Williams 	assert(details.st_size >= (__off_t)(RESPONSE_OFFSET + len));
795ab4e3e8SAndrew Jeffery 
805ab4e3e8SAndrew Jeffery 	rc = memcmp(expected, &map[RESPONSE_OFFSET], len);
815ab4e3e8SAndrew Jeffery 
825ab4e3e8SAndrew Jeffery 	if (rc != 0) {
835ab4e3e8SAndrew Jeffery 		printf("\nMBOX state (%ld):\n", details.st_size);
845ab4e3e8SAndrew Jeffery 		dump_buf(map, details.st_size);
855ab4e3e8SAndrew Jeffery 		printf("Expected response (%lu):\n", len);
865ab4e3e8SAndrew Jeffery 		dump_buf(expected, len);
875ab4e3e8SAndrew Jeffery 	}
885ab4e3e8SAndrew Jeffery 
895ab4e3e8SAndrew Jeffery 	munmap(map, details.st_size);
905ab4e3e8SAndrew Jeffery 
915ab4e3e8SAndrew Jeffery 	return rc;
925ab4e3e8SAndrew Jeffery }
935ab4e3e8SAndrew Jeffery 
mbox_rspcpy(struct mbox_context * context,struct mbox_msg * msg)94ca1dfc9eSAndrew Jeffery void mbox_rspcpy(struct mbox_context *context, struct mbox_msg *msg)
95ca1dfc9eSAndrew Jeffery {
96ca1dfc9eSAndrew Jeffery 	struct stat details;
97ca1dfc9eSAndrew Jeffery 	uint8_t *map;
98ca1dfc9eSAndrew Jeffery 	int fd;
99ca1dfc9eSAndrew Jeffery 
100ca1dfc9eSAndrew Jeffery 	fd = context->fds[MBOX_FD].fd;
101ca1dfc9eSAndrew Jeffery 	fstat(fd, &details);
102ca1dfc9eSAndrew Jeffery 
103ca1dfc9eSAndrew Jeffery 	map = mmap(NULL, details.st_size, PROT_READ, MAP_PRIVATE, fd, 0);
104ca1dfc9eSAndrew Jeffery 	assert(map != MAP_FAILED);
105ca1dfc9eSAndrew Jeffery 	assert(details.st_size >= (RESPONSE_OFFSET + RESPONSE_SIZE));
106ca1dfc9eSAndrew Jeffery 
107ca1dfc9eSAndrew Jeffery 	memcpy(msg, &map[RESPONSE_OFFSET], RESPONSE_SIZE);
108ca1dfc9eSAndrew Jeffery 
109ca1dfc9eSAndrew Jeffery 	munmap(map, details.st_size);
110ca1dfc9eSAndrew Jeffery }
111ca1dfc9eSAndrew Jeffery 
mbox_command_write(struct mbox_context * context,const uint8_t * command,size_t len)1125ab4e3e8SAndrew Jeffery int mbox_command_write(struct mbox_context *context, const uint8_t *command,
1135ab4e3e8SAndrew Jeffery 		size_t len)
1145ab4e3e8SAndrew Jeffery {
1155ab4e3e8SAndrew Jeffery 	size_t remaining;
1165ab4e3e8SAndrew Jeffery 	int rc;
1175ab4e3e8SAndrew Jeffery 	int fd;
1185ab4e3e8SAndrew Jeffery 
1195ab4e3e8SAndrew Jeffery 	fd = context->fds[MBOX_FD].fd;
1205ab4e3e8SAndrew Jeffery 	rc = lseek(fd, 0, SEEK_SET);
1215ab4e3e8SAndrew Jeffery 	if (rc != 0)
1225ab4e3e8SAndrew Jeffery 		return -1;
1235ab4e3e8SAndrew Jeffery 
1245ab4e3e8SAndrew Jeffery 	remaining = len;
1255ab4e3e8SAndrew Jeffery 	while (remaining > 0) {
1265ab4e3e8SAndrew Jeffery 		rc = write(fd, command, remaining);
1275ab4e3e8SAndrew Jeffery 		if (rc < 0)
1285ab4e3e8SAndrew Jeffery 			goto out;
1295ab4e3e8SAndrew Jeffery 		remaining -= rc;
1305ab4e3e8SAndrew Jeffery 	}
1315ab4e3e8SAndrew Jeffery 
1325ab4e3e8SAndrew Jeffery 	rc = lseek(fd, 0, SEEK_SET);
1335ab4e3e8SAndrew Jeffery 	if (rc != 0)
1345ab4e3e8SAndrew Jeffery 		return -1;
1355ab4e3e8SAndrew Jeffery 
1365ab4e3e8SAndrew Jeffery out:
1375ab4e3e8SAndrew Jeffery 	return rc;
1385ab4e3e8SAndrew Jeffery }
1395ab4e3e8SAndrew Jeffery 
mbox_command_dispatch(struct mbox_context * context,const uint8_t * command,size_t len)1405ab4e3e8SAndrew Jeffery int mbox_command_dispatch(struct mbox_context *context, const uint8_t *command,
1415ab4e3e8SAndrew Jeffery 		size_t len)
1425ab4e3e8SAndrew Jeffery {
1435ab4e3e8SAndrew Jeffery 	uint8_t status;
1445ab4e3e8SAndrew Jeffery 	int rc;
1455ab4e3e8SAndrew Jeffery 
1465ab4e3e8SAndrew Jeffery 	rc = mbox_command_write(context, command, len);
1475ab4e3e8SAndrew Jeffery 	if (rc < 0)
1485ab4e3e8SAndrew Jeffery 		return rc;
1495ab4e3e8SAndrew Jeffery 
150d86141b6SAndrew Jeffery 	rc = transport_mbox_dispatch(context);
1515ab4e3e8SAndrew Jeffery 	if (rc < 0)
1525ab4e3e8SAndrew Jeffery 		return -rc;
1535ab4e3e8SAndrew Jeffery 
1545ab4e3e8SAndrew Jeffery 	/*
1555ab4e3e8SAndrew Jeffery 	 * The aspeed-lpc-ctrl driver implements mailbox register access
1565ab4e3e8SAndrew Jeffery 	 * through the usual read()/write() chardev interface.
1575ab4e3e8SAndrew Jeffery 	 *
1585ab4e3e8SAndrew Jeffery 	 * The typical access sequence is:
1595ab4e3e8SAndrew Jeffery 	 *
1605ab4e3e8SAndrew Jeffery 	 * 1. Read all the registers out
1615ab4e3e8SAndrew Jeffery 	 * 2. Perform the action specified
1625ab4e3e8SAndrew Jeffery 	 * 3. Write a response to the registers.
1635ab4e3e8SAndrew Jeffery 	 *
1645ab4e3e8SAndrew Jeffery 	 * For the tests the "device" file descriptor is backed by a temporary
1655ab4e3e8SAndrew Jeffery 	 * file. The above sequence leads to a file-size of 30 bytes: 16 bytes
1665ab4e3e8SAndrew Jeffery 	 * for the issued command, followed by a 14-byte response.
1675ab4e3e8SAndrew Jeffery 	 *
1685ab4e3e8SAndrew Jeffery 	 * However, the typical access pattern isn't the only access pattern.
1695ab4e3e8SAndrew Jeffery 	 * Individual byte registers can be accessed by lseek()'ing on the
1705ab4e3e8SAndrew Jeffery 	 * device's file descriptor and issuing read() or write() as desired.
1715ab4e3e8SAndrew Jeffery 	 * The daemon uses this property to manage the BMC status byte, and the
1725ab4e3e8SAndrew Jeffery 	 * implementation cleans up after status byte operations by lseek()'ing
1735ab4e3e8SAndrew Jeffery 	 * back to offset zero.
1745ab4e3e8SAndrew Jeffery 	 *
1755ab4e3e8SAndrew Jeffery 	 * Thus for the BMC_EVENT_ACK command the file only reaches a size of
1765ab4e3e8SAndrew Jeffery 	 * 16 bytes; the daemon's response overwrites the first 14 bytes of the
1775ab4e3e8SAndrew Jeffery 	 * command injected by the tests.
1785ab4e3e8SAndrew Jeffery 	 *
1795ab4e3e8SAndrew Jeffery 	 * The consequence of this is that the response status byte can either
1805ab4e3e8SAndrew Jeffery 	 * appear at offset 13, or offset 29, depending on the command.
1815ab4e3e8SAndrew Jeffery 	 *
1825ab4e3e8SAndrew Jeffery 	 * However, regardless of what command is issued the response data is
1835ab4e3e8SAndrew Jeffery 	 * written to the device and the file descriptor is left in the
1845ab4e3e8SAndrew Jeffery 	 * post-write() state. This means the status byte can always be
1855ab4e3e8SAndrew Jeffery 	 * accessed relative to the current position by an lseek() of type
1865ab4e3e8SAndrew Jeffery 	 * SEEK_CUR for offset -1.
1875ab4e3e8SAndrew Jeffery 	 *
1885ab4e3e8SAndrew Jeffery 	 */
1895ab4e3e8SAndrew Jeffery 	rc = lseek(context->fds[MBOX_FD].fd, -1, SEEK_CUR);
1905ab4e3e8SAndrew Jeffery 	if (rc < 0)
1915ab4e3e8SAndrew Jeffery 		return rc;
1925ab4e3e8SAndrew Jeffery 
1935ab4e3e8SAndrew Jeffery 	rc = read(context->fds[MBOX_FD].fd, &status, sizeof(status));
1945ab4e3e8SAndrew Jeffery 	if (rc < 0)
1955ab4e3e8SAndrew Jeffery 		return rc;
1965ab4e3e8SAndrew Jeffery 
1975ab4e3e8SAndrew Jeffery 	return status;
1985ab4e3e8SAndrew Jeffery }
1995ab4e3e8SAndrew Jeffery 
2005ab4e3e8SAndrew Jeffery struct mbox_test_context {
2015ab4e3e8SAndrew Jeffery 	struct tmpf mbox;
2025ab4e3e8SAndrew Jeffery 	struct tmpf flash;
2035ab4e3e8SAndrew Jeffery 	struct tmpf lpc;
2045ab4e3e8SAndrew Jeffery 	struct mbox_context context;
2055ab4e3e8SAndrew Jeffery } test;
2065ab4e3e8SAndrew Jeffery 
cleanup(void)2075ab4e3e8SAndrew Jeffery void cleanup(void)
2085ab4e3e8SAndrew Jeffery {
2095ab4e3e8SAndrew Jeffery 	tmpf_destroy(&test.mbox);
2105ab4e3e8SAndrew Jeffery 	tmpf_destroy(&test.flash);
2115ab4e3e8SAndrew Jeffery 	tmpf_destroy(&test.lpc);
2125ab4e3e8SAndrew Jeffery }
2135ab4e3e8SAndrew Jeffery 
2144b8203d7SAndrew Jeffery int __transport_mbox_init(struct mbox_context *context, const char *path,
2154b8203d7SAndrew Jeffery 			  const struct transport_ops **ops);
216cb9b2100SAndrew Jeffery int __lpc_dev_init(struct mbox_context *context, const char *path);
2175ab4e3e8SAndrew Jeffery 
mbox_create_frontend_context(int n_windows,size_t len)218f1e547c7SEvan Lojewski struct mbox_context *mbox_create_frontend_context(int n_windows, size_t len)
2195ab4e3e8SAndrew Jeffery {
2204b8203d7SAndrew Jeffery 	const struct transport_ops *ops;
221f1e547c7SEvan Lojewski 	struct mtd_info_user mtd_info;
2225ab4e3e8SAndrew Jeffery 	int rc;
2235ab4e3e8SAndrew Jeffery 
2245ab4e3e8SAndrew Jeffery 	mbox_vlog = &mbox_log_console;
2255ab4e3e8SAndrew Jeffery 	verbosity = 2;
2265ab4e3e8SAndrew Jeffery 
2275ab4e3e8SAndrew Jeffery 	atexit(cleanup);
2285ab4e3e8SAndrew Jeffery 
229c3144042SAndrew Jeffery 	rc = tmpf_init(&test.mbox, "mbox-store.XXXXXX");
2305ab4e3e8SAndrew Jeffery 	assert(rc == 0);
2315ab4e3e8SAndrew Jeffery 
232c3144042SAndrew Jeffery 	rc = tmpf_init(&test.lpc, "lpc-store.XXXXXX");
2335ab4e3e8SAndrew Jeffery 	assert(rc == 0);
2345ab4e3e8SAndrew Jeffery 
2355ab4e3e8SAndrew Jeffery 	test.context.windows.num = n_windows;
2365ab4e3e8SAndrew Jeffery 	test.context.windows.default_size = len;
2375ab4e3e8SAndrew Jeffery 
2381e531afdSAndrew Jeffery 	rc = protocol_init(&test.context);
2391e531afdSAndrew Jeffery 	assert(rc == 0);
2401e531afdSAndrew Jeffery 
2415ab4e3e8SAndrew Jeffery 	/*
242b2466ee3SAndrew Jeffery 	 * We need to call __transport_mbox_init() to initialise the handler table.
243efb09defSAndrew Jeffery 	 * However, afterwards we need to discard the fd of the clearly useless
244efb09defSAndrew Jeffery 	 * /dev/null and replace it with our own fd for mbox device emulation
245efb09defSAndrew Jeffery 	 * by the test framework.
2465ab4e3e8SAndrew Jeffery 	 */
2474b8203d7SAndrew Jeffery 	__transport_mbox_init(&test.context, "/dev/null", &ops);
2484b8203d7SAndrew Jeffery 	test.context.transport = ops;
249efb09defSAndrew Jeffery 	rc = close(test.context.fds[MBOX_FD].fd);
250efb09defSAndrew Jeffery 	assert(rc == 0);
2515ab4e3e8SAndrew Jeffery 	test.context.fds[MBOX_FD].fd = test.mbox.fd;
2525ab4e3e8SAndrew Jeffery 
253f1e547c7SEvan Lojewski 	/* Instantiate the mtd backend */
254f1e547c7SEvan Lojewski 	rc = tmpf_init(&test.flash, "flash-store.XXXXXX");
2555ab4e3e8SAndrew Jeffery 	assert(rc == 0);
2565ab4e3e8SAndrew Jeffery 
257f1e547c7SEvan Lojewski 	rc = ioctl(test.flash.fd, MEMGETINFO, &mtd_info);
2585ab4e3e8SAndrew Jeffery 	assert(rc == 0);
2595ab4e3e8SAndrew Jeffery 
260f1e547c7SEvan Lojewski 	rc = fallocate(test.flash.fd, 0, 0, mtd_info.size);
261f1e547c7SEvan Lojewski 	assert(rc == 0);
262f1e547c7SEvan Lojewski 
263f1e547c7SEvan Lojewski 	test.context.backend.flash_size = mtd_info.size;
264f1e547c7SEvan Lojewski 
265cb9b2100SAndrew Jeffery 	rc = __lpc_dev_init(&test.context, test.lpc.path);
2665ab4e3e8SAndrew Jeffery 	assert(rc == 0);
2675ab4e3e8SAndrew Jeffery 
268d23affd4SAndrew Jeffery 	rc = fallocate(test.lpc.fd, 0, 0, test.context.mem_size);
2695ab4e3e8SAndrew Jeffery 	assert(rc == 0);
2705ab4e3e8SAndrew Jeffery 
271c1a67fa8SAndrew Jeffery 	rc = windows_init(&test.context);
2725ab4e3e8SAndrew Jeffery 	assert(rc == 0);
2735ab4e3e8SAndrew Jeffery 
2745ab4e3e8SAndrew Jeffery 	return rc ? NULL : &test.context;
2755ab4e3e8SAndrew Jeffery }
2765ab4e3e8SAndrew Jeffery 
mbox_create_test_context(int n_windows,size_t len)277f1e547c7SEvan Lojewski struct mbox_context *mbox_create_test_context(int n_windows, size_t len)
278f1e547c7SEvan Lojewski {
279f1e547c7SEvan Lojewski 	struct mbox_context *ctx;
280f1e547c7SEvan Lojewski 	int rc;
281f1e547c7SEvan Lojewski 
282f1e547c7SEvan Lojewski 	ctx = mbox_create_frontend_context(n_windows, len);
283f1e547c7SEvan Lojewski 	assert(ctx);
284f1e547c7SEvan Lojewski 
285f1e547c7SEvan Lojewski 	rc = backend_probe_mtd(&ctx->backend, test.flash.path);
286f1e547c7SEvan Lojewski 	assert(rc == 0);
287f1e547c7SEvan Lojewski 
288f1e547c7SEvan Lojewski 	return ctx;
289f1e547c7SEvan Lojewski }
290f1e547c7SEvan Lojewski 
2915ab4e3e8SAndrew Jeffery /* From ccan's container_of module, CC0 license */
2925ab4e3e8SAndrew Jeffery #define container_of(member_ptr, containing_type, member)		\
2935ab4e3e8SAndrew Jeffery 	 ((containing_type *)						\
2945ab4e3e8SAndrew Jeffery 	  ((char *)(member_ptr)						\
2955ab4e3e8SAndrew Jeffery 	   - container_off(containing_type, member))			\
2965ab4e3e8SAndrew Jeffery 	  + check_types_match(*(member_ptr), ((containing_type *)0)->member))
2975ab4e3e8SAndrew Jeffery 
2985ab4e3e8SAndrew Jeffery /* From ccan's container_of module, CC0 license */
2995ab4e3e8SAndrew Jeffery #define container_off(containing_type, member)	\
3005ab4e3e8SAndrew Jeffery 		offsetof(containing_type, member)
3015ab4e3e8SAndrew Jeffery 
3025ab4e3e8SAndrew Jeffery /* From ccan's check_type module, CC0 license */
3035ab4e3e8SAndrew Jeffery #define check_type(expr, type)			\
3045ab4e3e8SAndrew Jeffery 	((typeof(expr) *)0 != (type *)0)
3055ab4e3e8SAndrew Jeffery 
3065ab4e3e8SAndrew Jeffery /* From ccan's check_type module, CC0 license */
3075ab4e3e8SAndrew Jeffery #define check_types_match(expr1, expr2)		\
3085ab4e3e8SAndrew Jeffery 	((typeof(expr1) *)0 != (typeof(expr2) *)0)
3095ab4e3e8SAndrew Jeffery 
mbox_set_mtd_data(struct mbox_context * context,const void * data,size_t len)3105ab4e3e8SAndrew Jeffery int mbox_set_mtd_data(struct mbox_context *context, const void *data,
3115ab4e3e8SAndrew Jeffery 		size_t len)
3125ab4e3e8SAndrew Jeffery {
3135ab4e3e8SAndrew Jeffery 	struct mbox_test_context *arg;
3145ab4e3e8SAndrew Jeffery 	void *map;
3155ab4e3e8SAndrew Jeffery 
3167c1588aaSAndrew Jeffery 	assert(test.flash.fd > 2);
3177c1588aaSAndrew Jeffery 
3185ab4e3e8SAndrew Jeffery 	/* Sanity check */
3195ab4e3e8SAndrew Jeffery 	arg = container_of(context, struct mbox_test_context, context);
320bf2417e5SAndrew Jeffery 	assert(&test == arg);
321f1e547c7SEvan Lojewski 	assert(len <= test.context.backend.flash_size);
3225ab4e3e8SAndrew Jeffery 
323f1e547c7SEvan Lojewski 	map = mmap(NULL, test.context.backend.flash_size,
324f1e547c7SEvan Lojewski 		   PROT_WRITE, MAP_SHARED, test.flash.fd, 0);
3255ab4e3e8SAndrew Jeffery 	assert(map != MAP_FAILED);
3265ab4e3e8SAndrew Jeffery 	memcpy(map, data, len);
327f1e547c7SEvan Lojewski 	munmap(map, test.context.backend.flash_size);
3285ab4e3e8SAndrew Jeffery 
3295ab4e3e8SAndrew Jeffery 	return 0;
3305ab4e3e8SAndrew Jeffery }
3315ab4e3e8SAndrew Jeffery 
get_dev_mtd(void)3325ab4e3e8SAndrew Jeffery char *get_dev_mtd(void)
3335ab4e3e8SAndrew Jeffery {
3345ab4e3e8SAndrew Jeffery 	return strdup(test.flash.path);
3355ab4e3e8SAndrew Jeffery }
336