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
HieventOpen(struct file * filep)88 int HieventOpen(struct file *filep)
89 {
90 (void)filep;
91 return 0;
92 }
93
HieventClose(struct file * filep)94 int HieventClose(struct file *filep)
95 {
96 (void)filep;
97 return 0;
98 }
99
HieventBufferInc(size_t sz)100 static void HieventBufferInc(size_t sz)
101 {
102 if (g_hieventDev.size + sz <= HIEVENT_LOG_BUFFER) {
103 g_hieventDev.size += sz;
104 g_hieventDev.writeOffset += sz;
105 g_hieventDev.writeOffset %= HIEVENT_LOG_BUFFER;
106 g_hieventDev.count++;
107 }
108 }
109
HieventBufferDec(size_t sz)110 static void HieventBufferDec(size_t sz)
111 {
112 if (g_hieventDev.size >= sz) {
113 g_hieventDev.size -= sz;
114 g_hieventDev.headOffset += sz;
115 g_hieventDev.headOffset %= HIEVENT_LOG_BUFFER;
116 g_hieventDev.count--;
117 }
118 }
119
HieventBufferCopy(unsigned char * dst,unsigned dstLen,unsigned char * src,size_t srcLen)120 static int HieventBufferCopy(unsigned char *dst, unsigned dstLen,
121 unsigned char *src, size_t srcLen)
122 {
123 int retval = -1;
124
125 size_t minLen = dstLen > srcLen ? srcLen : dstLen;
126
127 if (LOS_IsUserAddressRange((vaddr_t)(uintptr_t)dst, minLen) &&
128 LOS_IsUserAddressRange((vaddr_t)(uintptr_t)src, minLen)) {
129 return retval;
130 }
131
132 if (LOS_IsUserAddressRange((vaddr_t)(uintptr_t)dst, minLen)) {
133 retval = LOS_ArchCopyToUser(dst, src, minLen);
134 } else if (LOS_IsUserAddressRange((vaddr_t)(uintptr_t)src, minLen)) {
135 retval = LOS_ArchCopyFromUser(dst, src, minLen);
136 } else {
137 retval = memcpy_s(dst, dstLen, src, srcLen);
138 }
139 return retval;
140 }
141
HieventReadRingBuffer(unsigned char * buffer,size_t bufLen)142 static int HieventReadRingBuffer(unsigned char *buffer, size_t bufLen)
143 {
144 int retval;
145 size_t bufLeft = HIEVENT_LOG_BUFFER - g_hieventDev.headOffset;
146 if (bufLeft > bufLen) {
147 retval = HieventBufferCopy(buffer, bufLen, HieventBufferHead(), bufLen);
148 } else {
149 retval = HieventBufferCopy(buffer, bufLen, HieventBufferHead(), bufLeft);
150 if (retval < 0) {
151 return retval;
152 }
153
154 retval = HieventBufferCopy(buffer + bufLeft, bufLen - bufLeft,
155 g_hieventDev.buffer, bufLen - bufLeft);
156 }
157 return retval;
158 }
159
HieventRead(struct file * filep,char * buffer,size_t bufLen)160 static ssize_t HieventRead(struct file *filep, char *buffer, size_t bufLen)
161 {
162 ssize_t retval;
163 struct HieventEntry header;
164
165 (void)filep;
166
167 wait_event_interruptible(g_hieventDev.wq, (g_hieventDev.size > 0));
168
169 (VOID)LOS_MuxAcquire(&g_hieventDev.mtx);
170
171 retval = HieventReadRingBuffer((unsigned char *)&header, sizeof(header));
172 if (retval < 0) {
173 retval = -EINVAL;
174 goto out;
175 }
176
177 if (bufLen < header.len + sizeof(header)) {
178 PRINT_ERR("buffer too small\n");
179 retval = -ENOMEM;
180 goto out;
181 }
182
183 HieventBufferDec(sizeof(header));
184
185 retval = HieventBufferCopy((unsigned char *)buffer, bufLen,
186 (unsigned char *)&header, sizeof(header));
187 if (retval < 0) {
188 retval = -EINVAL;
189 goto out;
190 }
191
192 retval = HieventReadRingBuffer((unsigned char *)(buffer + sizeof(header)),
193 header.len);
194 if (retval < 0) {
195 retval = -EINVAL;
196 goto out;
197 }
198
199 HieventBufferDec(header.len);
200
201 retval = header.len + sizeof(header);
202 out:
203 if (retval == -ENOMEM) {
204 // clean ring buffer
205 g_hieventDev.writeOffset = 0;
206 g_hieventDev.headOffset = 0;
207 g_hieventDev.size = 0;
208 g_hieventDev.count = 0;
209 }
210 (VOID)LOS_MuxRelease(&g_hieventDev.mtx);
211 return retval;
212 }
213
HieventWriteRingBuffer(unsigned char * buffer,size_t bufLen)214 static int HieventWriteRingBuffer(unsigned char *buffer, size_t bufLen)
215 {
216 int retval;
217 size_t bufLeft = HIEVENT_LOG_BUFFER - g_hieventDev.writeOffset;
218 if (bufLen > bufLeft) {
219 retval = HieventBufferCopy(g_hieventDev.buffer + g_hieventDev.writeOffset,
220 bufLeft, buffer, bufLeft);
221 if (retval) {
222 return -1;
223 }
224 retval = HieventBufferCopy(g_hieventDev.buffer, HIEVENT_LOG_BUFFER,
225 buffer + bufLeft, bufLen - bufLeft);
226 } else {
227 retval = HieventBufferCopy(g_hieventDev.buffer + g_hieventDev.writeOffset,
228 bufLeft, buffer, bufLen);
229 }
230 if (retval < 0) {
231 return -1;
232 }
233 return 0;
234 }
235
HieventHeadInit(struct HieventEntry * header,size_t len)236 static void HieventHeadInit(struct HieventEntry *header, size_t len)
237 {
238 struct timespec now;
239
240 clock_gettime(CLOCK_REALTIME, &now);
241
242 header->len = len;
243 header->pid = LOS_GetCurrProcessID();
244 header->tid = 0;
245 header->sec = now.tv_sec;
246 header->nsec = now.tv_nsec;
247 header->hdrSize = sizeof(struct HieventEntry);
248 }
249
HieventCoverOldLog(size_t bufLen)250 static void HieventCoverOldLog(size_t bufLen)
251 {
252 int retval;
253 struct HieventEntry header;
254 size_t totalSize = bufLen + sizeof(struct HieventEntry);
255
256 while (totalSize + g_hieventDev.size > HIEVENT_LOG_BUFFER) {
257 retval = HieventReadRingBuffer((unsigned char *)&header, sizeof(header));
258 if (retval < 0) {
259 break;
260 }
261
262 /* let count decrease twice */
263 HieventBufferDec(sizeof(header));
264 HieventBufferDec(header.len);
265 }
266 }
267
HieventWriteInternal(const char * buffer,size_t bufLen)268 int HieventWriteInternal(const char *buffer, size_t bufLen)
269 {
270 struct HieventEntry header;
271 int retval;
272
273 if (bufLen < sizeof(int) ||
274 bufLen > HIEVENT_LOG_BUFFER - sizeof(struct HieventEntry)) {
275 return -EINVAL;
276 }
277
278 (VOID)LOS_MuxAcquire(&g_hieventDev.mtx);
279
280 /* need userspace use writev */
281 if (LOS_IsUserAddressRange((vaddr_t)(uintptr_t)buffer, bufLen)) {
282 retval = -EINVAL;
283 goto out;
284 }
285
286 int checkCode = *((int *)buffer);
287
288 if (checkCode != CHECK_CODE) {
289 retval = -EINVAL;
290 goto out;
291 }
292
293 HieventCoverOldLog(bufLen);
294
295 HieventHeadInit(&header, bufLen - sizeof(int));
296
297 retval = HieventWriteRingBuffer((unsigned char *)&header, sizeof(header));
298 if (retval) {
299 retval = -EINVAL;
300 goto out;
301 }
302 HieventBufferInc(sizeof(header));
303
304 retval = HieventWriteRingBuffer((unsigned char *)(buffer + sizeof(int)),
305 header.len);
306 if (retval) {
307 retval = -EINVAL;
308 goto out;
309 }
310
311 HieventBufferInc(header.len);
312
313 retval = header.len;
314
315 out:
316 (VOID)LOS_MuxRelease(&g_hieventDev.mtx);
317 if (retval > 0) {
318 wake_up_interruptible(&g_hieventDev.wq);
319 }
320 return retval;
321 }
322
HieventWrite(struct file * filep,const char * buffer,size_t bufLen)323 static ssize_t HieventWrite(struct file *filep,
324 const char *buffer, size_t bufLen)
325 {
326 (void)filep;
327 return HieventWriteInternal(buffer, bufLen);
328 }
329
HieventPoll(struct file * filep,poll_table * fds)330 static int HieventPoll(struct file *filep, poll_table *fds)
331 {
332 (void)filep;
333
334 wait_event_interruptible(g_hieventDev.wq, (g_hieventDev.size > 0));
335
336 return (POLLOUT | POLLWRNORM);
337 }
338
HieventIoctl(struct file * filep,int cmd,unsigned long arg)339 static int HieventIoctl(struct file *filep, int cmd, unsigned long arg)
340 {
341 // not support ioctl in liteos now
342 (void)filep;
343 (void)cmd;
344 (void)arg;
345 return 0;
346 }
347
348 static struct file_operations_vfs g_hieventFops = {
349 .open = HieventOpen, /* open */
350 .close = HieventClose, /* close */
351 .read = HieventRead, /* read */
352 .write = HieventWrite, /* write */
353 .seek = NULL, /* seek */
354 .ioctl = HieventIoctl, /* ioctl */
355 .mmap = NULL, /* mmap */
356 .poll = HieventPoll, /* poll */
357 };
358
HieventDeviceInit(void)359 static int HieventDeviceInit(void)
360 {
361 g_hieventDev.buffer = LOS_MemAlloc((VOID *)OS_SYS_MEM_ADDR,
362 HIEVENT_LOG_BUFFER);
363 if (g_hieventDev.buffer == NULL) {
364 return -ENOMEM;
365 }
366
367 init_waitqueue_head(&g_hieventDev.wq);
368 (void)LOS_MuxInit(&g_hieventDev.mtx, NULL);
369
370 g_hieventDev.writeOffset = 0;
371 g_hieventDev.headOffset = 0;
372 g_hieventDev.size = 0;
373 g_hieventDev.count = 0;
374 return 0;
375 }
376
HieventInit(void)377 int HieventInit(void)
378 {
379 int ret = HieventDeviceInit();
380 if (ret != 0) {
381 return ret;
382 }
383
384 register_driver("/dev/hwlog_exception", &g_hieventFops,
385 DRIVER_MODE, &g_hieventDev);
386 return 0;
387 }
388
389 LOS_MODULE_INIT(HieventInit, LOS_INIT_LEVEL_KMOD_EXTENDED);
390