• 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 "los_hilog.h"
33 #include "los_init.h"
34 #include "los_mp.h"
35 #include "los_mux.h"
36 #include "los_process_pri.h"
37 #include "los_task_pri.h"
38 #include "fs/file.h"
39 #include "fs/driver.h"
40 #include "los_vm_map.h"
41 #include "los_vm_lock.h"
42 #include "user_copy.h"
43 
44 #define HILOG_BUFFER LOSCFG_HILOG_BUFFER_SIZE
45 #define DRIVER_MODE 0666
46 #define HILOG_DRIVER "/dev/hilog"
47 
48 struct HiLogEntry {
49     unsigned int len;
50     unsigned int hdrSize;
51     unsigned int pid : 16;
52     unsigned int taskId : 16;
53     unsigned int sec;
54     unsigned int nsec;
55     unsigned int reserved;
56     char msg[0];
57 };
58 
59 ssize_t HilogRead(struct file *filep, char __user *buf, size_t count);
60 ssize_t HilogWrite(struct file *filep, const char __user *buf, size_t count);
61 int HiLogOpen(struct file *filep);
62 int HiLogClose(struct file *filep);
63 
64 static ssize_t HiLogWrite(struct file *filep, const char *buffer, size_t bufLen);
65 static ssize_t HiLogRead(struct file *filep, char *buffer, size_t bufLen);
66 
67 STATIC struct file_operations_vfs g_hilogFops = {
68     HiLogOpen,  /* open */
69     HiLogClose, /* close */
70     HiLogRead,  /* read */
71     HiLogWrite, /* write */
72     NULL,       /* seek */
73     NULL,       /* ioctl */
74     NULL,       /* mmap */
75 #ifndef CONFIG_DISABLE_POLL
76     NULL, /* poll */
77 #endif
78     NULL, /* unlink */
79 };
80 
81 struct HiLogCharDevice {
82     int flag;
83     LosMux mtx;
84     unsigned char *buffer;
85     wait_queue_head_t wq;
86     size_t writeOffset;
87     size_t headOffset;
88     size_t size;
89     size_t count;
90 } g_hiLogDev;
91 
HiLogBufferHead(void)92 static inline unsigned char *HiLogBufferHead(void)
93 {
94     return g_hiLogDev.buffer + g_hiLogDev.headOffset;
95 }
96 
HiLogOpen(struct file * filep)97 int HiLogOpen(struct file *filep)
98 {
99     (void)filep;
100     return 0;
101 }
102 
HiLogClose(struct file * filep)103 int HiLogClose(struct file *filep)
104 {
105     (void)filep;
106     return 0;
107 }
108 
HiLogBufferInc(size_t sz)109 static void HiLogBufferInc(size_t sz)
110 {
111     if (g_hiLogDev.size + sz <= HILOG_BUFFER) {
112         g_hiLogDev.size += sz;
113         g_hiLogDev.writeOffset += sz;
114         g_hiLogDev.writeOffset %= HILOG_BUFFER;
115         g_hiLogDev.count++;
116     }
117 }
118 
HiLogBufferDec(size_t sz)119 static void HiLogBufferDec(size_t sz)
120 {
121     if (g_hiLogDev.size >= sz) {
122         g_hiLogDev.size -= sz;
123         g_hiLogDev.headOffset += sz;
124         g_hiLogDev.headOffset %= HILOG_BUFFER;
125         g_hiLogDev.count--;
126     }
127 }
128 
HiLogBufferCopy(unsigned char * dst,unsigned dstLen,const unsigned char * src,size_t srcLen)129 static int HiLogBufferCopy(unsigned char *dst, unsigned dstLen, const unsigned char *src, size_t srcLen)
130 {
131     int retval = -1;
132     size_t minLen = (dstLen > srcLen) ? srcLen : dstLen;
133 
134     if (LOS_IsUserAddressRange((VADDR_T)(UINTPTR)dst, minLen) &&
135         LOS_IsUserAddressRange((VADDR_T)(UINTPTR)src, minLen)) {
136         return retval;
137     }
138 
139     if (LOS_IsUserAddressRange((VADDR_T)(UINTPTR)dst, minLen)) {
140         retval = LOS_ArchCopyToUser(dst, src, minLen);
141     } else if (LOS_IsUserAddressRange((VADDR_T)(UINTPTR)src, minLen)) {
142         retval = LOS_ArchCopyFromUser(dst, src, minLen);
143     } else {
144         retval = memcpy_s(dst, dstLen, src, srcLen);
145     }
146     return retval;
147 }
148 
HiLogReadRingBuffer(unsigned char * buffer,size_t bufLen)149 static int HiLogReadRingBuffer(unsigned char *buffer, size_t bufLen)
150 {
151     int retval;
152     size_t bufLeft = HILOG_BUFFER - g_hiLogDev.headOffset;
153     if (bufLeft > bufLen) {
154         retval = HiLogBufferCopy(buffer, bufLen, HiLogBufferHead(), bufLen);
155     } else {
156         retval = HiLogBufferCopy(buffer, bufLen, HiLogBufferHead(), bufLeft);
157         if (retval < 0) {
158             return retval;
159         }
160 
161         retval = HiLogBufferCopy(buffer + bufLeft, bufLen - bufLeft, g_hiLogDev.buffer, bufLen - bufLeft);
162     }
163     return retval;
164 }
165 
HiLogRead(struct file * filep,char * buffer,size_t bufLen)166 static ssize_t HiLogRead(struct file *filep, char *buffer, size_t bufLen)
167 {
168     int retval;
169     struct HiLogEntry header;
170 
171     (void)filep;
172     wait_event_interruptible(g_hiLogDev.wq, (g_hiLogDev.size > 0));
173 
174     (VOID)LOS_MuxAcquire(&g_hiLogDev.mtx);
175     retval = HiLogReadRingBuffer((unsigned char *)&header, sizeof(header));
176     if (retval < 0) {
177         retval = -EINVAL;
178         goto out;
179     }
180 
181     if (bufLen < header.len + sizeof(header)) {
182         PRINTK("buffer too small,bufLen=%d, header.len=%d,%d\n", bufLen, header.len, header.hdrSize);
183         retval = -ENOMEM;
184         goto out;
185     }
186 
187     HiLogBufferDec(sizeof(header));
188 
189     retval = HiLogBufferCopy((unsigned char *)buffer, bufLen, (unsigned char *)&header, sizeof(header));
190     if (retval < 0) {
191         retval = -EINVAL;
192         goto out;
193     }
194 
195     retval = HiLogReadRingBuffer((unsigned char *)(buffer + sizeof(header)), header.len);
196     if (retval < 0) {
197         retval = -EINVAL;
198         goto out;
199     }
200 
201     HiLogBufferDec(header.len);
202     retval = header.len + sizeof(header);
203 out:
204     if (retval == -ENOMEM) {
205         // clean ring buffer
206         g_hiLogDev.writeOffset = 0;
207         g_hiLogDev.headOffset = 0;
208         g_hiLogDev.size = 0;
209         g_hiLogDev.count = 0;
210     }
211     (VOID)LOS_MuxRelease(&g_hiLogDev.mtx);
212     return (ssize_t)retval;
213 }
214 
HiLogWriteRingBuffer(unsigned char * buffer,size_t bufLen)215 static int HiLogWriteRingBuffer(unsigned char *buffer, size_t bufLen)
216 {
217     int retval;
218     size_t bufLeft = HILOG_BUFFER - g_hiLogDev.writeOffset;
219     if (bufLen > bufLeft) {
220         retval = HiLogBufferCopy(g_hiLogDev.buffer + g_hiLogDev.writeOffset, bufLeft, buffer, bufLeft);
221         if (retval) {
222             return -1;
223         }
224         retval = HiLogBufferCopy(g_hiLogDev.buffer, HILOG_BUFFER, buffer + bufLeft, bufLen - bufLeft);
225     } else {
226         retval = HiLogBufferCopy(g_hiLogDev.buffer + g_hiLogDev.writeOffset, bufLeft, buffer, bufLen);
227     }
228     if (retval < 0) {
229         return -1;
230     }
231     return 0;
232 }
233 
HiLogHeadInit(struct HiLogEntry * header,size_t len)234 static void HiLogHeadInit(struct HiLogEntry *header, size_t len)
235 {
236     struct timespec now = {0};
237     (void)clock_gettime(CLOCK_REALTIME, &now);
238 
239     header->len = len;
240     header->pid = LOS_GetCurrProcessID();
241     header->taskId = LOS_CurTaskIDGet();
242     header->sec = now.tv_sec;
243     header->nsec = now.tv_nsec;
244     header->hdrSize = sizeof(struct HiLogEntry);
245 }
246 
HiLogCoverOldLog(size_t bufLen)247 static void HiLogCoverOldLog(size_t bufLen)
248 {
249     int retval;
250     struct HiLogEntry header;
251     size_t totalSize = bufLen + sizeof(struct HiLogEntry);
252     static int dropLogLines = 0;
253     static int isLastTimeFull = 0;
254     int isThisTimeFull = 0;
255 
256     while (totalSize + g_hiLogDev.size > HILOG_BUFFER) {
257         retval = HiLogReadRingBuffer((unsigned char *)&header, sizeof(header));
258         if (retval < 0) {
259             break;
260         }
261 
262         dropLogLines++;
263         isThisTimeFull = 1;
264         isLastTimeFull = 1;
265         HiLogBufferDec(sizeof(header));
266         HiLogBufferDec(header.len);
267     }
268     if (isLastTimeFull == 1 && isThisTimeFull == 0) {
269         /* so we can only print one log if hilog ring buffer is full in a short time */
270         if (dropLogLines > 0) {
271             PRINTK("hilog ringbuffer full, drop %d line(s) log\n", dropLogLines);
272         }
273         isLastTimeFull = 0;
274         dropLogLines = 0;
275     }
276 }
277 
HiLogWriteInternal(const char * buffer,size_t bufLen)278 int HiLogWriteInternal(const char *buffer, size_t bufLen)
279 {
280     struct HiLogEntry header;
281     int retval;
282     LosTaskCB *runTask =  (LosTaskCB *)OsCurrTaskGet();
283 
284     if ((g_hiLogDev.buffer == NULL) || (OS_INT_ACTIVE) || (runTask->taskStatus & OS_TASK_FLAG_SYSTEM_TASK)) {
285         PRINTK("%s\n", buffer);
286         return -EAGAIN;
287     }
288 
289     (VOID)LOS_MuxAcquire(&g_hiLogDev.mtx);
290     HiLogCoverOldLog(bufLen);
291     HiLogHeadInit(&header, bufLen);
292 
293     retval = HiLogWriteRingBuffer((unsigned char *)&header, sizeof(header));
294     if (retval) {
295         retval = -ENODATA;
296         goto out;
297     }
298     HiLogBufferInc(sizeof(header));
299 
300     retval = HiLogWriteRingBuffer((unsigned char *)(buffer), header.len);
301     if (retval) {
302         retval = -ENODATA;
303         goto out;
304     }
305 
306     HiLogBufferInc(header.len);
307 
308     retval = header.len;
309 
310 out:
311     (VOID)LOS_MuxRelease(&g_hiLogDev.mtx);
312     if (retval > 0) {
313         wake_up_interruptible(&g_hiLogDev.wq);
314     }
315     if (retval < 0) {
316         PRINTK("write fail retval=%d\n", retval);
317     }
318     return retval;
319 }
320 
HiLogWrite(struct file * filep,const char * buffer,size_t bufLen)321 static ssize_t HiLogWrite(struct file *filep, const char *buffer, size_t bufLen)
322 {
323     (void)filep;
324     size_t totalBufLen = bufLen + sizeof(struct HiLogEntry);
325     if ((totalBufLen < bufLen) || (totalBufLen > HILOG_BUFFER)) {
326         PRINTK("input bufLen %lld too large\n", bufLen);
327         return -ENOMEM;
328     }
329 
330     return HiLogWriteInternal(buffer, bufLen);
331 }
332 
HiLogDeviceInit(void)333 static void HiLogDeviceInit(void)
334 {
335     g_hiLogDev.buffer = LOS_MemAlloc((VOID *)OS_SYS_MEM_ADDR, HILOG_BUFFER);
336     if (g_hiLogDev.buffer == NULL) {
337         PRINTK("In %s line %d,LOS_MemAlloc fail\n", __FUNCTION__, __LINE__);
338     }
339 
340     init_waitqueue_head(&g_hiLogDev.wq);
341     LOS_MuxInit(&g_hiLogDev.mtx, NULL);
342 
343     g_hiLogDev.writeOffset = 0;
344     g_hiLogDev.headOffset = 0;
345     g_hiLogDev.size = 0;
346     g_hiLogDev.count = 0;
347 }
348 
OsHiLogDriverInit(VOID)349 int OsHiLogDriverInit(VOID)
350 {
351     HiLogDeviceInit();
352     return register_driver(HILOG_DRIVER, &g_hilogFops, DRIVER_MODE, NULL);
353 }
354 
355 LOS_MODULE_INIT(OsHiLogDriverInit, LOS_INIT_LEVEL_KMOD_EXTENDED);
356