1 /*
2 * Copyright (c) 2013-2019 Huawei Technologies Co., Ltd. All rights reserved.
3 * Copyright (c) 2020-2021 Huawei Device Co., Ltd. All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without modification,
6 * are permitted provided that the following conditions are met:
7 *
8 * 1. Redistributions of source code must retain the above copyright notice, this list of
9 * conditions and the following disclaimer.
10 *
11 * 2. Redistributions in binary form must reproduce the above copyright notice, this list
12 * of conditions and the following disclaimer in the documentation and/or other materials
13 * provided with the distribution.
14 *
15 * 3. Neither the name of the copyright holder nor the names of its contributors may be used
16 * to endorse or promote products derived from this software without specific prior written
17 * permission.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
20 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
21 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
23 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
24 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
25 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
26 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
27 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
28 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
29 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30 */
31
32 #include "hievent_driver.h"
33
34 #include <assert.h>
35 #include <errno.h>
36 #include <fcntl.h>
37 #include <fs/driver.h>
38 #include <linux/list.h>
39 #include <linux/wait.h>
40 #include <semaphore.h>
41 #include <stdio.h>
42 #include <sys/types.h>
43 #include <unistd.h>
44
45 #include "los_init.h"
46 #include "los_memory.h"
47 #include "los_mp.h"
48 #include "los_mux.h"
49 #include "los_process_pri.h"
50 #include "los_task_pri.h"
51 #include "los_vm_lock.h"
52 #include "los_vm_map.h"
53 #include "poll.h"
54 #include "user_copy.h"
55
56 #define HIEVENT_LOG_BUFFER 1024
57 #define DRIVER_MODE 0666
58
59 struct HieventEntry {
60 uint16_t len;
61 uint16_t hdrSize;
62 int32_t pid;
63 int32_t tid;
64 int32_t sec;
65 int32_t nsec;
66 char msg[0];
67 };
68
69 struct HieventCharDevice {
70 int flag;
71 LosMux mtx;
72 unsigned char *buffer;
73 wait_queue_head_t wq;
74 size_t writeOffset;
75 size_t headOffset;
76 size_t size;
77 size_t count;
78 } g_hieventDev;
79
HieventBufferHead(void)80 static inline unsigned char *HieventBufferHead(void)
81 {
82 if (g_hieventDev.headOffset > HIEVENT_LOG_BUFFER) {
83 g_hieventDev.headOffset = g_hieventDev.headOffset % HIEVENT_LOG_BUFFER;
84 }
85 return g_hieventDev.buffer + g_hieventDev.headOffset;
86 }
87
88
HieventOpen(struct file * filep)89 int HieventOpen(struct file *filep)
90 {
91 (void)filep;
92 return 0;
93 }
94
HieventClose(struct file * filep)95 int HieventClose(struct file *filep)
96 {
97 (void)filep;
98 return 0;
99 }
100
HieventBufferInc(size_t sz)101 static void HieventBufferInc(size_t sz)
102 {
103 if (g_hieventDev.size + sz <= HIEVENT_LOG_BUFFER) {
104 g_hieventDev.size += sz;
105 g_hieventDev.writeOffset += sz;
106 g_hieventDev.writeOffset %= HIEVENT_LOG_BUFFER;
107 g_hieventDev.count++;
108 }
109 }
110
HieventBufferDec(size_t sz)111 static void HieventBufferDec(size_t sz)
112 {
113 if (g_hieventDev.size >= sz) {
114 g_hieventDev.size -= sz;
115 g_hieventDev.headOffset += sz;
116 g_hieventDev.headOffset %= HIEVENT_LOG_BUFFER;
117 g_hieventDev.count--;
118 }
119 }
120
HieventBufferCopy(unsigned char * dst,unsigned dstLen,unsigned char * src,size_t srcLen)121 static int HieventBufferCopy(unsigned char *dst, unsigned dstLen,
122 unsigned char *src, size_t srcLen)
123 {
124 int retval = -1;
125
126 size_t minLen = dstLen > srcLen ? srcLen : dstLen;
127
128 if (LOS_IsUserAddressRange((vaddr_t)(uintptr_t)dst, minLen) &&
129 LOS_IsUserAddressRange((vaddr_t)(uintptr_t)src, minLen)) {
130 return retval;
131 }
132
133 if (LOS_IsUserAddressRange((vaddr_t)(uintptr_t)dst, minLen)) {
134 retval = LOS_ArchCopyToUser(dst, src, minLen);
135 } else if (LOS_IsUserAddressRange((vaddr_t)(uintptr_t)src, minLen)) {
136 retval = LOS_ArchCopyFromUser(dst, src, minLen);
137 } else {
138 retval = memcpy_s(dst, dstLen, src, srcLen);
139 }
140 return retval;
141 }
142
HieventReadRingBuffer(unsigned char * buffer,size_t bufLen)143 static int HieventReadRingBuffer(unsigned char *buffer, size_t bufLen)
144 {
145 int retval;
146 size_t bufLeft = HIEVENT_LOG_BUFFER - g_hieventDev.headOffset;
147 if (bufLeft > bufLen) {
148 retval = HieventBufferCopy(buffer, bufLen, HieventBufferHead(), bufLen);
149 } else {
150 retval = HieventBufferCopy(buffer, bufLen, HieventBufferHead(), bufLeft);
151 if (retval < 0) {
152 return retval;
153 }
154
155 retval = HieventBufferCopy(buffer + bufLeft, bufLen - bufLeft,
156 g_hieventDev.buffer, bufLen - bufLeft);
157 }
158 return retval;
159 }
160
HieventRead(struct file * filep,char * buffer,size_t bufLen)161 static ssize_t HieventRead(struct file *filep, char *buffer, size_t bufLen)
162 {
163 ssize_t retval;
164 struct HieventEntry header;
165
166 (void)filep;
167
168 wait_event_interruptible(g_hieventDev.wq, (g_hieventDev.size > 0));
169
170 (VOID)LOS_MuxAcquire(&g_hieventDev.mtx);
171
172 retval = HieventReadRingBuffer((unsigned char *)&header, sizeof(header));
173 if (retval < 0) {
174 retval = -EINVAL;
175 goto out;
176 }
177
178 if (bufLen < header.len + sizeof(header)) {
179 PRINT_ERR("buffer too small\n");
180 retval = -ENOMEM;
181 goto out;
182 }
183
184 HieventBufferDec(sizeof(header));
185
186 retval = HieventBufferCopy((unsigned char *)buffer, bufLen,
187 (unsigned char *)&header, sizeof(header));
188 if (retval < 0) {
189 retval = -EINVAL;
190 goto out;
191 }
192
193 retval = HieventReadRingBuffer((unsigned char *)(buffer + sizeof(header)),
194 header.len);
195 if (retval < 0) {
196 retval = -EINVAL;
197 goto out;
198 }
199
200 HieventBufferDec(header.len);
201
202 retval = header.len + sizeof(header);
203 out:
204 if (retval == -ENOMEM) {
205 // clean ring buffer
206 g_hieventDev.writeOffset = 0;
207 g_hieventDev.headOffset = 0;
208 g_hieventDev.size = 0;
209 g_hieventDev.count = 0;
210 }
211 (VOID)LOS_MuxRelease(&g_hieventDev.mtx);
212 return retval;
213
214 }
215
HieventWriteRingBuffer(unsigned char * buffer,size_t bufLen)216 static int HieventWriteRingBuffer(unsigned char *buffer, size_t bufLen)
217 {
218 int retval;
219 size_t bufLeft = HIEVENT_LOG_BUFFER - g_hieventDev.writeOffset;
220 if (bufLen > bufLeft) {
221 retval = HieventBufferCopy(g_hieventDev.buffer + g_hieventDev.writeOffset,
222 bufLeft, buffer, bufLeft);
223 if (retval) {
224 return -1;
225 }
226 retval = HieventBufferCopy(g_hieventDev.buffer, HIEVENT_LOG_BUFFER,
227 buffer + bufLeft, bufLen - bufLeft);
228 } else {
229 retval = HieventBufferCopy(g_hieventDev.buffer + g_hieventDev.writeOffset,
230 bufLeft, buffer, bufLen);
231 }
232 if (retval < 0) {
233 return -1;
234 }
235 return 0;
236 }
237
HieventHeadInit(struct HieventEntry * header,size_t len)238 static void HieventHeadInit(struct HieventEntry *header, size_t len)
239 {
240 struct timespec now;
241
242 clock_gettime(CLOCK_REALTIME, &now);
243
244 header->len = len;
245 header->pid = LOS_GetCurrProcessID();
246 header->tid = 0;
247 header->sec = now.tv_sec;
248 header->nsec = now.tv_nsec;
249 header->hdrSize = sizeof(struct HieventEntry);
250 }
251
HieventCoverOldLog(size_t bufLen)252 static void HieventCoverOldLog(size_t bufLen)
253 {
254 int retval;
255 struct HieventEntry header;
256 size_t totalSize = bufLen + sizeof(struct HieventEntry);
257
258 while (totalSize + g_hieventDev.size > HIEVENT_LOG_BUFFER) {
259 retval = HieventReadRingBuffer((unsigned char *)&header, sizeof(header));
260 if (retval < 0) {
261 break;
262 }
263
264 /* let count decrease twice */
265 HieventBufferDec(sizeof(header));
266 HieventBufferDec(header.len);
267 }
268 }
269
HieventWriteInternal(const char * buffer,size_t bufLen)270 int HieventWriteInternal(const char *buffer, size_t bufLen)
271 {
272 struct HieventEntry header;
273 int retval;
274
275 if (bufLen < sizeof(int) ||
276 bufLen > HIEVENT_LOG_BUFFER - sizeof(struct HieventEntry)) {
277 return -EINVAL;
278 }
279
280 (VOID)LOS_MuxAcquire(&g_hieventDev.mtx);
281
282 /* need userspace use writev */
283 if (LOS_IsUserAddressRange((vaddr_t)(uintptr_t)buffer, bufLen)) {
284 retval = -EINVAL;
285 goto out;
286 }
287
288 int checkCode = *((int *)buffer);
289
290 if (checkCode != CHECK_CODE) {
291 retval = -EINVAL;
292 goto out;
293 }
294
295 HieventCoverOldLog(bufLen);
296
297 HieventHeadInit(&header, bufLen - sizeof(int));
298
299 retval = HieventWriteRingBuffer((unsigned char *)&header, sizeof(header));
300 if (retval) {
301 retval = -EINVAL;
302 goto out;
303 }
304 HieventBufferInc(sizeof(header));
305
306 retval = HieventWriteRingBuffer((unsigned char *)(buffer + sizeof(int)),
307 header.len);
308 if (retval) {
309 retval = -EINVAL;
310 goto out;
311 }
312
313 HieventBufferInc(header.len);
314
315 retval = header.len;
316
317 out:
318 (VOID)LOS_MuxRelease(&g_hieventDev.mtx);
319 if (retval > 0) {
320 wake_up_interruptible(&g_hieventDev.wq);
321 }
322 return retval;
323
324 }
325
HieventWrite(struct file * filep,const char * buffer,size_t bufLen)326 static ssize_t HieventWrite(struct file *filep,
327 const char *buffer, size_t bufLen)
328 {
329 (void)filep;
330 return HieventWriteInternal(buffer, bufLen);
331 }
332
HieventPoll(struct file * filep,poll_table * fds)333 static int HieventPoll(struct file *filep, poll_table *fds)
334 {
335 (void)filep;
336
337 wait_event_interruptible(g_hieventDev.wq, (g_hieventDev.size > 0));
338
339 return (POLLOUT | POLLWRNORM);
340 }
341
HieventIoctl(struct file * filep,int cmd,unsigned long arg)342 static int HieventIoctl(struct file *filep, int cmd, unsigned long arg)
343 {
344 // not support ioctl in liteos now
345 (void)filep;
346 (void)cmd;
347 (void)arg;
348 return 0;
349 }
350
351 static struct file_operations_vfs g_hieventFops = {
352 .open = HieventOpen, /* open */
353 .close = HieventClose, /* close */
354 .read = HieventRead, /* read */
355 .write = HieventWrite, /* write */
356 .seek = NULL, /* seek */
357 .ioctl = HieventIoctl, /* ioctl */
358 .mmap = NULL, /* mmap */
359 .poll = HieventPoll, /* poll */
360 };
361
HieventDeviceInit(void)362 static int HieventDeviceInit(void)
363 {
364 g_hieventDev.buffer = LOS_MemAlloc((VOID *)OS_SYS_MEM_ADDR,
365 HIEVENT_LOG_BUFFER);
366 if (g_hieventDev.buffer == NULL) {
367 return -ENOMEM;
368 }
369
370 init_waitqueue_head(&g_hieventDev.wq);
371 (void)LOS_MuxInit(&g_hieventDev.mtx, NULL);
372
373 g_hieventDev.writeOffset = 0;
374 g_hieventDev.headOffset = 0;
375 g_hieventDev.size = 0;
376 g_hieventDev.count = 0;
377 return 0;
378 }
379
HieventInit(void)380 int HieventInit(void)
381 {
382 int ret = HieventDeviceInit();
383 if (ret != 0) {
384 return ret;
385 }
386
387 register_driver("/dev/hwlog_exception", &g_hieventFops,
388 DRIVER_MODE, &g_hieventDev);
389 return 0;
390 }
391
392 LOS_MODULE_INIT(HieventInit, LOS_INIT_LEVEL_KMOD_EXTENDED);
393