blob: c224b8450e8c8786e43456afba48addcd6fb572a [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>
Evan Lojewskif1e547c2019-03-14 14:34:33 +103011#include <sys/ioctl.h>
Andrew Jeffery5ab4e3e2017-04-12 14:23:24 +093012#include <sys/mman.h>
13#include <sys/types.h>
14#include <sys/stat.h>
15#include <unistd.h>
16
Evan Lojewskif1e547c2019-03-14 14:34:33 +103017#include "config.h"
Andrew Jeffery26558db2018-08-10 00:22:38 +093018#include "mboxd.h"
Evan Lojewskif1e547c2019-03-14 14:34:33 +103019#include "backend.h"
Andrew Jefferycd186112018-08-08 10:47:55 +093020#include "lpc.h"
Andrew Jeffery457a6e52018-08-08 11:21:08 +093021#include "transport_mbox.h"
Andrew Jefferyf593b1b2018-08-08 11:01:04 +093022#include "windows.h"
Andrew Jeffery5ab4e3e2017-04-12 14:23:24 +093023
24#include "test/mbox.h"
25
26#define STEP 16
27
Andrew Jefferyee7af882018-03-01 11:57:50 +103028void dump_buf(const void *buf, size_t len)
Andrew Jeffery5ab4e3e2017-04-12 14:23:24 +093029{
Andrew Jefferyee7af882018-03-01 11:57:50 +103030 const uint8_t *buf8 = buf;
Andrew Jeffery5ab4e3e2017-04-12 14:23:24 +093031 int i;
32
33 for (i = 0; i < len; i += STEP) {
34 int delta;
35 int max;
36 int j;
37
38 delta = len - i;
39 max = delta > STEP ? STEP : delta;
40
41 printf("0x%08x:\t", i);
42 for (j = 0; j < max; j++)
Andrew Jefferyee7af882018-03-01 11:57:50 +103043 printf("0x%02x, ", buf8[i + j]);
Andrew Jeffery5ab4e3e2017-04-12 14:23:24 +093044
45 printf("\n");
46 }
47 printf("\n");
48}
49
50/*
51 * Because we are using a file and not a pipe for the mbox file descriptor we
52 * need to handle a difference in behaviour. For a given command and response
53 * sequence the first 16 bytes of the file are occupied by the mbox command.
54 * The response occupies the following 14 bytes for a total of 30 bytes.
55 *
56 * We also have to ensure we lseek() to reset the file descriptor offset back
57 * to the start of the file before dispatching the mbox command.
58 */
59
60/* Macros for handling the pipe/file discrepancy */
61#define RESPONSE_OFFSET 16
62#define RESPONSE_SIZE 14
63
64int mbox_cmp(struct mbox_context *context, const uint8_t *expected, size_t len)
65{
66 struct stat details;
67 uint8_t *map;
68 int rc;
69 int fd;
70
71 fd = context->fds[MBOX_FD].fd;
72 fstat(fd, &details);
73
74 map = mmap(NULL, details.st_size, PROT_READ, MAP_PRIVATE, fd, 0);
Andrew Jeffery23a48212018-08-10 14:41:48 +093075 printf("%s:%d: details.st_size: %ld, RESPONSE_OFFSET + len: %ld\n",
76 __func__, __LINE__, details.st_size, RESPONSE_OFFSET + len);
Andrew Jeffery5ab4e3e2017-04-12 14:23:24 +093077 assert(map != MAP_FAILED);
78 assert(details.st_size >= (RESPONSE_OFFSET + len));
79
80 rc = memcmp(expected, &map[RESPONSE_OFFSET], len);
81
82 if (rc != 0) {
83 printf("\nMBOX state (%ld):\n", details.st_size);
84 dump_buf(map, details.st_size);
85 printf("Expected response (%lu):\n", len);
86 dump_buf(expected, len);
87 }
88
89 munmap(map, details.st_size);
90
91 return rc;
92}
93
Andrew Jefferyca1dfc92018-03-22 16:49:40 +103094void mbox_rspcpy(struct mbox_context *context, struct mbox_msg *msg)
95{
96 struct stat details;
97 uint8_t *map;
98 int fd;
99
100 fd = context->fds[MBOX_FD].fd;
101 fstat(fd, &details);
102
103 map = mmap(NULL, details.st_size, PROT_READ, MAP_PRIVATE, fd, 0);
104 assert(map != MAP_FAILED);
105 assert(details.st_size >= (RESPONSE_OFFSET + RESPONSE_SIZE));
106
107 memcpy(msg, &map[RESPONSE_OFFSET], RESPONSE_SIZE);
108
109 munmap(map, details.st_size);
110}
111
Andrew Jeffery5ab4e3e2017-04-12 14:23:24 +0930112int mbox_command_write(struct mbox_context *context, const uint8_t *command,
113 size_t len)
114{
115 size_t remaining;
116 int rc;
117 int fd;
118
119 fd = context->fds[MBOX_FD].fd;
120 rc = lseek(fd, 0, SEEK_SET);
121 if (rc != 0)
122 return -1;
123
124 remaining = len;
125 while (remaining > 0) {
126 rc = write(fd, command, remaining);
127 if (rc < 0)
128 goto out;
129 remaining -= rc;
130 }
131
132 rc = lseek(fd, 0, SEEK_SET);
133 if (rc != 0)
134 return -1;
135
136out:
137 return rc;
138}
139
140int mbox_command_dispatch(struct mbox_context *context, const uint8_t *command,
141 size_t len)
142{
143 uint8_t status;
144 int rc;
145
146 rc = mbox_command_write(context, command, len);
147 if (rc < 0)
148 return rc;
149
Andrew Jefferyd86141b2018-08-09 14:58:53 +0930150 rc = transport_mbox_dispatch(context);
Andrew Jeffery5ab4e3e2017-04-12 14:23:24 +0930151 if (rc < 0)
152 return -rc;
153
154 /*
155 * The aspeed-lpc-ctrl driver implements mailbox register access
156 * through the usual read()/write() chardev interface.
157 *
158 * The typical access sequence is:
159 *
160 * 1. Read all the registers out
161 * 2. Perform the action specified
162 * 3. Write a response to the registers.
163 *
164 * For the tests the "device" file descriptor is backed by a temporary
165 * file. The above sequence leads to a file-size of 30 bytes: 16 bytes
166 * for the issued command, followed by a 14-byte response.
167 *
168 * However, the typical access pattern isn't the only access pattern.
169 * Individual byte registers can be accessed by lseek()'ing on the
170 * device's file descriptor and issuing read() or write() as desired.
171 * The daemon uses this property to manage the BMC status byte, and the
172 * implementation cleans up after status byte operations by lseek()'ing
173 * back to offset zero.
174 *
175 * Thus for the BMC_EVENT_ACK command the file only reaches a size of
176 * 16 bytes; the daemon's response overwrites the first 14 bytes of the
177 * command injected by the tests.
178 *
179 * The consequence of this is that the response status byte can either
180 * appear at offset 13, or offset 29, depending on the command.
181 *
182 * However, regardless of what command is issued the response data is
183 * written to the device and the file descriptor is left in the
184 * post-write() state. This means the status byte can always be
185 * accessed relative to the current position by an lseek() of type
186 * SEEK_CUR for offset -1.
187 *
188 */
189 rc = lseek(context->fds[MBOX_FD].fd, -1, SEEK_CUR);
190 if (rc < 0)
191 return rc;
192
193 rc = read(context->fds[MBOX_FD].fd, &status, sizeof(status));
194 if (rc < 0)
195 return rc;
196
197 return status;
198}
199
200struct mbox_test_context {
201 struct tmpf mbox;
202 struct tmpf flash;
203 struct tmpf lpc;
204 struct mbox_context context;
205} test;
206
207void cleanup(void)
208{
209 tmpf_destroy(&test.mbox);
210 tmpf_destroy(&test.flash);
211 tmpf_destroy(&test.lpc);
212}
213
Andrew Jeffery4b8203d2019-05-06 14:36:16 +0930214int __transport_mbox_init(struct mbox_context *context, const char *path,
215 const struct transport_ops **ops);
Andrew Jefferycb9b2102018-08-08 16:31:07 +0930216int __lpc_dev_init(struct mbox_context *context, const char *path);
Andrew Jeffery5ab4e3e2017-04-12 14:23:24 +0930217
Evan Lojewskif1e547c2019-03-14 14:34:33 +1030218struct mbox_context *mbox_create_frontend_context(int n_windows, size_t len)
Andrew Jeffery5ab4e3e2017-04-12 14:23:24 +0930219{
Andrew Jeffery4b8203d2019-05-06 14:36:16 +0930220 const struct transport_ops *ops;
Evan Lojewskif1e547c2019-03-14 14:34:33 +1030221 struct mtd_info_user mtd_info;
Andrew Jeffery5ab4e3e2017-04-12 14:23:24 +0930222 int rc;
223
224 mbox_vlog = &mbox_log_console;
225 verbosity = 2;
226
227 atexit(cleanup);
228
Andrew Jefferyc3144042018-02-26 13:24:52 +1030229 rc = tmpf_init(&test.mbox, "mbox-store.XXXXXX");
Andrew Jeffery5ab4e3e2017-04-12 14:23:24 +0930230 assert(rc == 0);
231
Andrew Jefferyc3144042018-02-26 13:24:52 +1030232 rc = tmpf_init(&test.lpc, "lpc-store.XXXXXX");
Andrew Jeffery5ab4e3e2017-04-12 14:23:24 +0930233 assert(rc == 0);
234
235 test.context.windows.num = n_windows;
236 test.context.windows.default_size = len;
237
Andrew Jeffery1e531af2018-08-07 13:32:57 +0930238 rc = protocol_init(&test.context);
239 assert(rc == 0);
240
Andrew Jeffery5ab4e3e2017-04-12 14:23:24 +0930241 /*
Andrew Jefferyb2466ee2018-08-09 15:03:27 +0930242 * We need to call __transport_mbox_init() to initialise the handler table.
Andrew Jefferyefb09de2018-03-26 14:36:43 +1030243 * However, afterwards we need to discard the fd of the clearly useless
244 * /dev/null and replace it with our own fd for mbox device emulation
245 * by the test framework.
Andrew Jeffery5ab4e3e2017-04-12 14:23:24 +0930246 */
Andrew Jeffery4b8203d2019-05-06 14:36:16 +0930247 __transport_mbox_init(&test.context, "/dev/null", &ops);
248 test.context.transport = ops;
Andrew Jefferyefb09de2018-03-26 14:36:43 +1030249 rc = close(test.context.fds[MBOX_FD].fd);
250 assert(rc == 0);
Andrew Jeffery5ab4e3e2017-04-12 14:23:24 +0930251 test.context.fds[MBOX_FD].fd = test.mbox.fd;
252
Evan Lojewskif1e547c2019-03-14 14:34:33 +1030253 /* Instantiate the mtd backend */
254 rc = tmpf_init(&test.flash, "flash-store.XXXXXX");
Andrew Jeffery5ab4e3e2017-04-12 14:23:24 +0930255 assert(rc == 0);
256
Evan Lojewskif1e547c2019-03-14 14:34:33 +1030257 rc = ioctl(test.flash.fd, MEMGETINFO, &mtd_info);
Andrew Jeffery5ab4e3e2017-04-12 14:23:24 +0930258 assert(rc == 0);
259
Evan Lojewskif1e547c2019-03-14 14:34:33 +1030260 rc = fallocate(test.flash.fd, 0, 0, mtd_info.size);
261 assert(rc == 0);
262
263 test.context.backend.flash_size = mtd_info.size;
264
Andrew Jefferycb9b2102018-08-08 16:31:07 +0930265 rc = __lpc_dev_init(&test.context, test.lpc.path);
Andrew Jeffery5ab4e3e2017-04-12 14:23:24 +0930266 assert(rc == 0);
267
Andrew Jefferyd23affd2018-03-23 12:13:39 +1030268 rc = fallocate(test.lpc.fd, 0, 0, test.context.mem_size);
Andrew Jeffery5ab4e3e2017-04-12 14:23:24 +0930269 assert(rc == 0);
270
Andrew Jefferyc1a67fa2018-08-08 17:07:38 +0930271 rc = windows_init(&test.context);
Andrew Jeffery5ab4e3e2017-04-12 14:23:24 +0930272 assert(rc == 0);
273
274 return rc ? NULL : &test.context;
275}
276
Evan Lojewskif1e547c2019-03-14 14:34:33 +1030277struct mbox_context *mbox_create_test_context(int n_windows, size_t len)
278{
279 struct mbox_context *ctx;
280 int rc;
281
282 ctx = mbox_create_frontend_context(n_windows, len);
283 assert(ctx);
284
285 rc = backend_probe_mtd(&ctx->backend, test.flash.path);
286 assert(rc == 0);
287
288 return ctx;
289}
290
Andrew Jeffery5ab4e3e2017-04-12 14:23:24 +0930291/* From ccan's container_of module, CC0 license */
292#define container_of(member_ptr, containing_type, member) \
293 ((containing_type *) \
294 ((char *)(member_ptr) \
295 - container_off(containing_type, member)) \
296 + check_types_match(*(member_ptr), ((containing_type *)0)->member))
297
298/* From ccan's container_of module, CC0 license */
299#define container_off(containing_type, member) \
300 offsetof(containing_type, member)
301
302/* From ccan's check_type module, CC0 license */
303#define check_type(expr, type) \
304 ((typeof(expr) *)0 != (type *)0)
305
306/* From ccan's check_type module, CC0 license */
307#define check_types_match(expr1, expr2) \
308 ((typeof(expr1) *)0 != (typeof(expr2) *)0)
309
310int mbox_set_mtd_data(struct mbox_context *context, const void *data,
311 size_t len)
312{
313 struct mbox_test_context *arg;
314 void *map;
315
Andrew Jeffery7c1588a2019-03-14 14:57:40 +1030316 assert(test.flash.fd > 2);
317
Andrew Jeffery5ab4e3e2017-04-12 14:23:24 +0930318 /* Sanity check */
319 arg = container_of(context, struct mbox_test_context, context);
Andrew Jefferybf2417e2019-03-14 14:56:34 +1030320 assert(&test == arg);
Evan Lojewskif1e547c2019-03-14 14:34:33 +1030321 assert(len <= test.context.backend.flash_size);
Andrew Jeffery5ab4e3e2017-04-12 14:23:24 +0930322
Evan Lojewskif1e547c2019-03-14 14:34:33 +1030323 map = mmap(NULL, test.context.backend.flash_size,
324 PROT_WRITE, MAP_SHARED, test.flash.fd, 0);
Andrew Jeffery5ab4e3e2017-04-12 14:23:24 +0930325 assert(map != MAP_FAILED);
326 memcpy(map, data, len);
Evan Lojewskif1e547c2019-03-14 14:34:33 +1030327 munmap(map, test.context.backend.flash_size);
Andrew Jeffery5ab4e3e2017-04-12 14:23:24 +0930328
329 return 0;
330}
331
332char *get_dev_mtd(void)
333{
334 return strdup(test.flash.path);
335}