• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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