blob: f7560f1fb628a8353ad54c35238a8a837001c0ce [file] [log] [blame]
Andrew Jeffery4fe996c2018-02-27 12:16:48 +10301// SPDX-License-Identifier: Apache-2.0
2// Copyright (C) 2018 IBM Corp.
Andrew Jeffery5ab4e3e2017-04-12 14:23:24 +09303
4#define _GNU_SOURCE /* fallocate */
5#include <assert.h>
6#include <fcntl.h>
7#include <stdint.h>
8#include <stdio.h>
9#include <stdlib.h>
10#include <string.h>
11#include <sys/mman.h>
12#include <sys/types.h>
13#include <sys/stat.h>
14#include <unistd.h>
15
Andrew Jeffery26558db2018-08-10 00:22:38 +093016#include "mboxd.h"
Andrew Jefferyeebc6bd2018-08-08 10:38:19 +093017#include "flash.h"
Andrew Jefferycd186112018-08-08 10:47:55 +093018#include "lpc.h"
Andrew Jeffery457a6e52018-08-08 11:21:08 +093019#include "transport_mbox.h"
Andrew Jefferyf593b1b2018-08-08 11:01:04 +093020#include "windows.h"
Andrew Jeffery5ab4e3e2017-04-12 14:23:24 +093021
22#include "test/mbox.h"
23
24#define STEP 16
25
Andrew Jefferyee7af882018-03-01 11:57:50 +103026void dump_buf(const void *buf, size_t len)
Andrew Jeffery5ab4e3e2017-04-12 14:23:24 +093027{
Andrew Jefferyee7af882018-03-01 11:57:50 +103028 const uint8_t *buf8 = buf;
Andrew Jeffery5ab4e3e2017-04-12 14:23:24 +093029 int i;
30
31 for (i = 0; i < len; i += STEP) {
32 int delta;
33 int max;
34 int j;
35
36 delta = len - i;
37 max = delta > STEP ? STEP : delta;
38
39 printf("0x%08x:\t", i);
40 for (j = 0; j < max; j++)
Andrew Jefferyee7af882018-03-01 11:57:50 +103041 printf("0x%02x, ", buf8[i + j]);
Andrew Jeffery5ab4e3e2017-04-12 14:23:24 +093042
43 printf("\n");
44 }
45 printf("\n");
46}
47
48/*
49 * Because we are using a file and not a pipe for the mbox file descriptor we
50 * need to handle a difference in behaviour. For a given command and response
51 * sequence the first 16 bytes of the file are occupied by the mbox command.
52 * The response occupies the following 14 bytes for a total of 30 bytes.
53 *
54 * We also have to ensure we lseek() to reset the file descriptor offset back
55 * to the start of the file before dispatching the mbox command.
56 */
57
58/* Macros for handling the pipe/file discrepancy */
59#define RESPONSE_OFFSET 16
60#define RESPONSE_SIZE 14
61
62int mbox_cmp(struct mbox_context *context, const uint8_t *expected, size_t len)
63{
64 struct stat details;
65 uint8_t *map;
66 int rc;
67 int fd;
68
69 fd = context->fds[MBOX_FD].fd;
70 fstat(fd, &details);
71
72 map = mmap(NULL, details.st_size, PROT_READ, MAP_PRIVATE, fd, 0);
Andrew Jeffery23a48212018-08-10 14:41:48 +093073 printf("%s:%d: details.st_size: %ld, RESPONSE_OFFSET + len: %ld\n",
74 __func__, __LINE__, details.st_size, RESPONSE_OFFSET + len);
Andrew Jeffery5ab4e3e2017-04-12 14:23:24 +093075 assert(map != MAP_FAILED);
76 assert(details.st_size >= (RESPONSE_OFFSET + len));
77
78 rc = memcmp(expected, &map[RESPONSE_OFFSET], len);
79
80 if (rc != 0) {
81 printf("\nMBOX state (%ld):\n", details.st_size);
82 dump_buf(map, details.st_size);
83 printf("Expected response (%lu):\n", len);
84 dump_buf(expected, len);
85 }
86
87 munmap(map, details.st_size);
88
89 return rc;
90}
91
Andrew Jefferyca1dfc92018-03-22 16:49:40 +103092void mbox_rspcpy(struct mbox_context *context, struct mbox_msg *msg)
93{
94 struct stat details;
95 uint8_t *map;
96 int fd;
97
98 fd = context->fds[MBOX_FD].fd;
99 fstat(fd, &details);
100
101 map = mmap(NULL, details.st_size, PROT_READ, MAP_PRIVATE, fd, 0);
102 assert(map != MAP_FAILED);
103 assert(details.st_size >= (RESPONSE_OFFSET + RESPONSE_SIZE));
104
105 memcpy(msg, &map[RESPONSE_OFFSET], RESPONSE_SIZE);
106
107 munmap(map, details.st_size);
108}
109
Andrew Jeffery5ab4e3e2017-04-12 14:23:24 +0930110int mbox_command_write(struct mbox_context *context, const uint8_t *command,
111 size_t len)
112{
113 size_t remaining;
114 int rc;
115 int fd;
116
117 fd = context->fds[MBOX_FD].fd;
118 rc = lseek(fd, 0, SEEK_SET);
119 if (rc != 0)
120 return -1;
121
122 remaining = len;
123 while (remaining > 0) {
124 rc = write(fd, command, remaining);
125 if (rc < 0)
126 goto out;
127 remaining -= rc;
128 }
129
130 rc = lseek(fd, 0, SEEK_SET);
131 if (rc != 0)
132 return -1;
133
134out:
135 return rc;
136}
137
138int mbox_command_dispatch(struct mbox_context *context, const uint8_t *command,
139 size_t len)
140{
141 uint8_t status;
142 int rc;
143
144 rc = mbox_command_write(context, command, len);
145 if (rc < 0)
146 return rc;
147
Andrew Jefferyd86141b2018-08-09 14:58:53 +0930148 rc = transport_mbox_dispatch(context);
Andrew Jeffery5ab4e3e2017-04-12 14:23:24 +0930149 if (rc < 0)
150 return -rc;
151
152 /*
153 * The aspeed-lpc-ctrl driver implements mailbox register access
154 * through the usual read()/write() chardev interface.
155 *
156 * The typical access sequence is:
157 *
158 * 1. Read all the registers out
159 * 2. Perform the action specified
160 * 3. Write a response to the registers.
161 *
162 * For the tests the "device" file descriptor is backed by a temporary
163 * file. The above sequence leads to a file-size of 30 bytes: 16 bytes
164 * for the issued command, followed by a 14-byte response.
165 *
166 * However, the typical access pattern isn't the only access pattern.
167 * Individual byte registers can be accessed by lseek()'ing on the
168 * device's file descriptor and issuing read() or write() as desired.
169 * The daemon uses this property to manage the BMC status byte, and the
170 * implementation cleans up after status byte operations by lseek()'ing
171 * back to offset zero.
172 *
173 * Thus for the BMC_EVENT_ACK command the file only reaches a size of
174 * 16 bytes; the daemon's response overwrites the first 14 bytes of the
175 * command injected by the tests.
176 *
177 * The consequence of this is that the response status byte can either
178 * appear at offset 13, or offset 29, depending on the command.
179 *
180 * However, regardless of what command is issued the response data is
181 * written to the device and the file descriptor is left in the
182 * post-write() state. This means the status byte can always be
183 * accessed relative to the current position by an lseek() of type
184 * SEEK_CUR for offset -1.
185 *
186 */
187 rc = lseek(context->fds[MBOX_FD].fd, -1, SEEK_CUR);
188 if (rc < 0)
189 return rc;
190
191 rc = read(context->fds[MBOX_FD].fd, &status, sizeof(status));
192 if (rc < 0)
193 return rc;
194
195 return status;
196}
197
198struct mbox_test_context {
199 struct tmpf mbox;
200 struct tmpf flash;
201 struct tmpf lpc;
202 struct mbox_context context;
203} test;
204
205void cleanup(void)
206{
207 tmpf_destroy(&test.mbox);
208 tmpf_destroy(&test.flash);
209 tmpf_destroy(&test.lpc);
210}
211
Andrew Jefferyb2466ee2018-08-09 15:03:27 +0930212int __transport_mbox_init(struct mbox_context *context, const char *path);
Andrew Jefferycb9b2102018-08-08 16:31:07 +0930213int __lpc_dev_init(struct mbox_context *context, const char *path);
Andrew Jeffery5ab4e3e2017-04-12 14:23:24 +0930214
215struct mbox_context *mbox_create_test_context(int n_windows, size_t len)
216{
217 int rc;
218
219 mbox_vlog = &mbox_log_console;
220 verbosity = 2;
221
222 atexit(cleanup);
223
Andrew Jefferyc3144042018-02-26 13:24:52 +1030224 rc = tmpf_init(&test.mbox, "mbox-store.XXXXXX");
Andrew Jeffery5ab4e3e2017-04-12 14:23:24 +0930225 assert(rc == 0);
226
Andrew Jefferyc3144042018-02-26 13:24:52 +1030227 rc = tmpf_init(&test.flash, "flash-store.XXXXXX");
Andrew Jeffery5ab4e3e2017-04-12 14:23:24 +0930228 assert(rc == 0);
229
Andrew Jefferyc3144042018-02-26 13:24:52 +1030230 rc = tmpf_init(&test.lpc, "lpc-store.XXXXXX");
Andrew Jeffery5ab4e3e2017-04-12 14:23:24 +0930231 assert(rc == 0);
232
233 test.context.windows.num = n_windows;
234 test.context.windows.default_size = len;
235
Andrew Jeffery1e531af2018-08-07 13:32:57 +0930236 rc = protocol_init(&test.context);
237 assert(rc == 0);
238
Andrew Jeffery5ab4e3e2017-04-12 14:23:24 +0930239 /*
Andrew Jefferyb2466ee2018-08-09 15:03:27 +0930240 * We need to call __transport_mbox_init() to initialise the handler table.
Andrew Jefferyefb09de2018-03-26 14:36:43 +1030241 * However, afterwards we need to discard the fd of the clearly useless
242 * /dev/null and replace it with our own fd for mbox device emulation
243 * by the test framework.
Andrew Jeffery5ab4e3e2017-04-12 14:23:24 +0930244 */
Andrew Jefferyb2466ee2018-08-09 15:03:27 +0930245 __transport_mbox_init(&test.context, "/dev/null");
Andrew Jefferyefb09de2018-03-26 14:36:43 +1030246 rc = close(test.context.fds[MBOX_FD].fd);
247 assert(rc == 0);
Andrew Jeffery5ab4e3e2017-04-12 14:23:24 +0930248 test.context.fds[MBOX_FD].fd = test.mbox.fd;
249
Andrew Jefferyd6b09bc2018-08-08 16:47:54 +0930250 rc = flash_dev_init(&test.context);
Andrew Jeffery5ab4e3e2017-04-12 14:23:24 +0930251 assert(rc == 0);
252
253 rc = fallocate(test.flash.fd, 0, 0, test.context.mtd_info.size);
254 assert(rc == 0);
255
Andrew Jefferycb9b2102018-08-08 16:31:07 +0930256 rc = __lpc_dev_init(&test.context, test.lpc.path);
Andrew Jeffery5ab4e3e2017-04-12 14:23:24 +0930257 assert(rc == 0);
258
Andrew Jefferyd23affd2018-03-23 12:13:39 +1030259 rc = fallocate(test.lpc.fd, 0, 0, test.context.mem_size);
Andrew Jeffery5ab4e3e2017-04-12 14:23:24 +0930260 assert(rc == 0);
261
Andrew Jefferyc1a67fa2018-08-08 17:07:38 +0930262 rc = windows_init(&test.context);
Andrew Jeffery5ab4e3e2017-04-12 14:23:24 +0930263 assert(rc == 0);
264
265 return rc ? NULL : &test.context;
266}
267
268/* From ccan's container_of module, CC0 license */
269#define container_of(member_ptr, containing_type, member) \
270 ((containing_type *) \
271 ((char *)(member_ptr) \
272 - container_off(containing_type, member)) \
273 + check_types_match(*(member_ptr), ((containing_type *)0)->member))
274
275/* From ccan's container_of module, CC0 license */
276#define container_off(containing_type, member) \
277 offsetof(containing_type, member)
278
279/* From ccan's check_type module, CC0 license */
280#define check_type(expr, type) \
281 ((typeof(expr) *)0 != (type *)0)
282
283/* From ccan's check_type module, CC0 license */
284#define check_types_match(expr1, expr2) \
285 ((typeof(expr1) *)0 != (typeof(expr2) *)0)
286
287int mbox_set_mtd_data(struct mbox_context *context, const void *data,
288 size_t len)
289{
290 struct mbox_test_context *arg;
291 void *map;
292
293 /* Sanity check */
294 arg = container_of(context, struct mbox_test_context, context);
295 if (&test != arg)
296 return -1;
297
298 if (len > test.context.mtd_info.size)
299 return -2;
300
301 map = mmap(NULL, test.context.mtd_info.size, PROT_WRITE, MAP_SHARED,
302 test.flash.fd, 0);
303 assert(map != MAP_FAILED);
304 memcpy(map, data, len);
305 munmap(map, test.context.mtd_info.size);
306
307 return 0;
308}
309
310char *get_dev_mtd(void)
311{
312 return strdup(test.flash.path);
313}