Merge tag 'v4.4-rc1'
[firefly-linux-kernel-4.4.55.git] / security / tlk_driver / ote_log.c
1 /*
2  * Copyright (c) 2013-2014 NVIDIA Corporation. All rights reserved.
3  *
4  * This program is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation; either version 2 of the License, or
7  * (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful, but WITHOUT
10  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
12  * more details.
13  *
14  * You should have received a copy of the GNU General Public License along
15  * with this program; if not, write to the Free Software Foundation, Inc.,
16  * 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
17  */
18
19 #include <linux/slab.h>
20 #include <linux/syscalls.h>
21 #include <linux/list.h>
22 #include <linux/completion.h>
23 #include <linux/workqueue.h>
24 #include <linux/bitops.h>
25 #include <linux/uaccess.h>
26
27 #include <asm/page.h>
28 #include <linux/dma-mapping.h>
29 #include <linux/string.h>
30
31 #include "ote_protocol.h"
32
33 #define LOGBUF_SIZE 8192
34
35 struct circular_buffer {
36         uint32_t size; /* Indicates the total size of the buffer */
37         uint32_t start; /* Starting point of valid data in buffer */
38         uint32_t end; /* First character which is empty (can be written to) */
39         uint32_t overflow; /* Indicator whether buffer has overwritten itself */
40         char *buf;
41 };
42
43 #if defined(CONFIG_OTE_ENABLE_LOGGER)
44
45 static int ote_logging_enabled;
46 struct circular_buffer *cb;
47
48 /*
49  * Initialize the shared buffer for TLK logging.
50  * The shared buffer is allocated in DMA memory to get uncached memory
51  * since TLK directly writes to the physical address of the shared buffer.
52  * The structure is declared in DMA memory too since it's members will
53  * also be updated by the TLK directly to their physical addresses.
54  */
55 static int circ_buf_init(struct circular_buffer **cbptr)
56 {
57
58         dma_addr_t tp;
59
60         *cbptr = (struct circular_buffer *) dma_alloc_coherent(NULL,
61                         sizeof(struct circular_buffer), &tp, GFP_KERNEL);
62         if (!*cbptr) {
63                 pr_err("%s: no memory avaiable for circular buffer struct\n",
64                         __func__);
65                 return -ENOMEM;
66         }
67         memset(*cbptr, 0, sizeof(struct circular_buffer));
68
69         (*cbptr)->start = 0;
70         (*cbptr)->end = 0;
71         (*cbptr)->size = LOGBUF_SIZE;
72
73         (*cbptr)->buf = (char *) dma_alloc_coherent(NULL, LOGBUF_SIZE,
74                         &tp, GFP_KERNEL);
75         if (!(*cbptr)->buf) {
76                         pr_err("%s: no memory avaiable for shared buffer\n",
77                                 __func__);
78                 /* Frees the memory allocated using dma_alloc_coherent */
79                         dma_free_coherent(NULL,
80                                 sizeof(struct circular_buffer), cbptr, tp);
81                         return -ENOMEM;
82         }
83         memset((*cbptr)->buf, 0, LOGBUF_SIZE);
84
85         (*cbptr)->overflow = 0;
86
87         return 0;
88 }
89
90 /*
91  * Copy the contents of the circular buffer into a char buffer in order.
92  * This helps to treat the buffer like a string and use it to tokenize it
93  * into lines, tag and display it.
94  */
95 static int circ_buf_copy(struct circular_buffer *cb, char *text)
96 {
97         if (cb->end == cb->start)
98                 return 0;
99
100         if (cb->end > cb->start) {
101                 if (abs(cb->end - cb->start) > LOGBUF_SIZE) {
102                         pr_err("%s: cbuf pointers corrupted\n", __func__);
103                         return -EINVAL;
104                 }
105
106                 memcpy(text, cb->buf + cb->start, cb->end - cb->start);
107
108         } else if (cb->start > cb->end) {
109                 if (abs(cb->end - cb->start) > LOGBUF_SIZE) {
110                         pr_err("%s: cbuf pointers corrupted\n", __func__);
111                         return -EINVAL;
112                 }
113
114                 memcpy(text, cb->buf + cb->start, cb->size - cb->start);
115                 memcpy(text + cb->size - cb->start, cb->buf, cb->end);
116
117         }
118
119         return 0;
120 }
121
122 /*
123  * Function which prints TLK logs.
124  * Tokenizes the TLK logs into lines, tags each line
125  * and prints it out to kmsg file.
126  */
127 void ote_print_logs(void)
128 {
129         char *text = NULL;
130         char *temp = NULL;
131         char *buffer = NULL;
132
133         if (!ote_logging_enabled)
134                 return;
135
136         buffer = kzalloc(LOGBUF_SIZE, GFP_KERNEL);
137         BUG_ON(!buffer);
138
139         /* This detects if the buffer proved to be too small to hold the data.
140          * If buffer is not large enough, it overwrites it's oldest data,
141          * This warning serves to alert the user to possibly use a bigger buffer
142          */
143         if (cb->overflow == 1) {
144                 pr_info("\n[TLK] **WARNING** TLK buffer overwritten.\n\n");
145                 cb->overflow = 0;
146         }
147
148         if (circ_buf_copy(cb, buffer) != 0) {
149                 kfree(buffer);
150                 return;
151         }
152         cb->buf[cb->end] = '\0';
153
154         /* In case no delimiter was found,
155          * the token is taken to be the entire string *stringp,
156          * and *stringp is made NULL.
157          */
158         text = buffer;
159         temp = strsep(&text, "\n");
160         while (temp != NULL) {
161                 if (strnlen(temp, LOGBUF_SIZE))
162                         pr_info("[TLK] %s\n", temp);
163                 temp = strsep(&text, "\n");
164         }
165
166         /* Indicate that buffer is empty */
167         cb->start = cb->end;
168         kfree(buffer);
169 }
170 #else
171 void ote_print_logs(void) {}
172 #endif
173
174 /*
175  * Call function to initialize circular buffer.
176  * An SMC is made to send the virtual address of the structure to
177  * the secure OS.
178  */
179 static int __init ote_logger_init(void)
180 {
181         uintptr_t smc_args[MAX_EXT_SMC_ARGS];
182
183 #if defined(CONFIG_OTE_ENABLE_LOGGER)
184         if (circ_buf_init(&cb) != 0)
185                 return -1;
186
187         smc_args[0] = TE_SMC_INIT_LOGGER;
188         smc_args[1] = (uintptr_t)cb;
189
190         /* enable logging only if secure firmware supports it */
191         if (!tlk_generic_smc(smc_args[0], smc_args[1], 0))
192                 ote_logging_enabled = 1;
193
194         ote_print_logs();
195 #else
196         smc_args[0] = TE_SMC_INIT_LOGGER;
197         smc_args[1] = 0;
198         tlk_generic_smc(smc_args[0], smc_args[1], 0);
199 #endif
200
201         return 0;
202 }
203
204 arch_initcall(ote_logger_init);