Apply secure-storage data migration
[platform/core/telephony/tel-plugin-imc.git] / src / nvm / nvm.c
1 /*
2  * tel-plugin-imc
3  *
4  * Copyright (c) 2012 Samsung Electronics Co., Ltd. All rights reserved.
5  *
6  * Contact: Paresh Agarwal <paresh.agwl@samsung.com>
7  *
8  * Licensed under the Apache License, Version 2.0 (the "License");
9  * you may not use this file except in compliance with the License.
10  * You may obtain a copy of the License at
11  *
12  * http://www.apache.org/licenses/LICENSE-2.0
13  *
14  * Unless required by applicable law or agreed to in writing, software
15  * distributed under the License is distributed on an "AS IS" BASIS,
16  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17  * See the License for the specific language governing permissions and
18  * limitations under the License.
19  */
20
21 #include <fcntl.h>
22 #include <stdio.h>
23 #include <stdlib.h>
24 #include <unistd.h>
25 #include <glib.h>
26 #include <string.h>
27
28 #include <sys/stat.h>
29 #include <tcore.h>
30 #include "nvm/nvm.h"
31
32 /* NVM file type */
33 #define NVM_TYPE_CALIB                  0
34 #define NVM_TYPE_STATIC         1
35 #define NVM_TYPE_DYNAMIC                2
36 #define NVM_FILE_TYPE_POS               36
37
38 /* NVM Payload information */
39 #define NVM_PAYLOAD_OFFSET_0            48
40 #define NVM_PAYLOAD_LENGTH_0            52
41 #define NVM_PAYLOAD_OFFSET_1            64
42 #define NVM_PAYLOAD_LENGTH_1            68
43 #define NVM_DATA_LEN_POS                80
44
45 /* Image Path information */
46 #define MODEM_IMAGE_PATH                "/opt/modem/modem.bin"
47 #define NVM_DIR_PATH                    "/csa/nv"
48 #define NV_FILE_PATH                    NVM_DIR_PATH"/nvdata.bin"
49
50 /* NV offsets and size */
51 #define MODEM_NV_OFFSET         0xA00000
52 #define MAX_NVDATA_SIZE         0x200000
53 #define NVM_CALIB_OFFSET                0x80000
54 #define NVM_STATIC_OFFSET               0x100000
55
56 struct nvm_payload_info {
57         unsigned long m_offset_0;
58         unsigned long m_length_0;
59         unsigned long m_offset_1;
60         unsigned long m_length_1;
61 };
62
63 static nvm_error __nvm_file_write(int nvm_type, const char *update_buf, int update_len, int offset)
64 {
65         int nv_fd;
66         nvm_error ret_val = NVM_NO_ERR;
67         int ret;
68
69         char err_str[256] = {0, };
70         errno = 0;
71         dbg("Entered");
72
73         if (NULL == update_buf) {
74                 err("Buffer is invalid!!!");
75                 return NVM_WRITE_ERR;
76         }
77
78         switch (nvm_type) {
79         case NVM_TYPE_CALIB:
80                 msg("           [NVM File] calib.nvm");
81                 offset = offset + NVM_CALIB_OFFSET;
82                 break;
83
84         case NVM_TYPE_STATIC:
85                 msg("           [NVM File] static.nvm");
86                 offset = offset + NVM_STATIC_OFFSET;
87                 break;
88
89         case NVM_TYPE_DYNAMIC:
90                 msg("           [NVM File] dynamic.nvm");
91                 break;
92
93         default:
94                 err("[NVM File] Wrong NVM file type: [%d]", nvm_type);
95                 return NVM_FILE_ERR;
96         }
97
98         /* Open NVM file for Write operation */
99         nv_fd = open(NV_FILE_PATH, O_RDWR);
100         if (nv_fd < 0) {
101                 strerror_r(errno, err_str, 255);
102                 err("[OPEN] Failed: [%s]", err_str);
103                 return NVM_READ_ERR;
104         }
105
106         /* Seek the offset */
107         ret = lseek(nv_fd, (long)offset, SEEK_SET);
108         if (ret < 0) {
109                 strerror_r(errno, err_str, 255);
110                 err("[SEEK] Failed: [%s]", err_str);
111                 ret_val = NVM_RES_LEN_ERR;
112         } else {
113                 dbg("Buffer: [0x%x] length: [%d]", update_buf, update_len);
114
115                 /* Write the buffer to file */
116                 ret = write(nv_fd, update_buf, update_len);
117                 if (ret > 0) {
118                         dbg("[WRITE] Successfully updated NVM data");
119                 } else if (ret == 0) {
120                         strerror_r(errno, err_str, 255);
121                         dbg("[WRITE] Nothing is written: [%s]", err_str);
122                 } else {
123                         strerror_r(errno, err_str, 255);
124                         err("[WRITE] Failed: [%s]", err_str);
125                         ret_val = NVM_MEM_FULL_ERR;
126                 }
127         }
128
129         /* Close 'fd' */
130         close(nv_fd);
131
132         return ret_val;
133 }
134
135 static nvm_error __nvm_write_payload_1(int nvm_type,
136                                                 const char *p_bin_buff, struct nvm_payload_info *nvm1)
137 {
138         const char *p_buf_ptr = p_bin_buff;
139
140         /* Write to file */
141         return __nvm_file_write(nvm_type,
142                                         (p_buf_ptr + NVM_DATA_LEN_POS + nvm1->m_length_0),
143                                         nvm1->m_length_1,
144                                         nvm1->m_offset_1);
145 }
146
147 static nvm_error __nvm_write_payload_0(int nvm_type,
148                                                 const char *p_bin_buff, struct nvm_payload_info *nvm)
149 {
150         nvm_error ret_val;
151
152         /* Write to file */
153         ret_val = __nvm_file_write(nvm_type,
154                                         (p_bin_buff + NVM_DATA_LEN_POS),
155                                         nvm->m_length_0,
156                                         nvm->m_offset_0);
157         if (NVM_NO_ERR == ret_val) {
158                 /* The payload_0 has been done, so calls this method to write payload_1 to file */
159                 ret_val = __nvm_write_payload_1(nvm_type, p_bin_buff, nvm);
160         } else {
161                 err("Failed to write to NV data file!!!");
162         }
163
164         return ret_val;
165 }
166
167 int nvm_sum_4_bytes(const char *pos)
168 {
169         int sum = 0;
170         sum = sum | (*(pos+3)) << 24;
171         sum = sum | (*(pos+2)) << 16;
172         sum = sum | (*(pos+1)) << 8;
173         sum = sum | *pos;
174         return sum;
175 }
176
177 nvm_error nvm_process_nv_update(const char *data)
178 {
179         struct nvm_payload_info nvm_info;
180         int nvm_type;
181         nvm_error ret_val;
182         dbg("Entered");
183
184         memset(&nvm_info, 0x0, sizeof(struct nvm_payload_info));
185
186         /* Determine lengths from the little-endian 4 bytes */
187         nvm_info.m_length_0 = nvm_sum_4_bytes(&data[NVM_PAYLOAD_LENGTH_0]);
188         nvm_info.m_offset_0 = nvm_sum_4_bytes(&data[NVM_PAYLOAD_OFFSET_0]);
189         nvm_info.m_length_1 = nvm_sum_4_bytes(&data[NVM_PAYLOAD_LENGTH_1]);
190         nvm_info.m_offset_1 = nvm_sum_4_bytes(&data[NVM_PAYLOAD_OFFSET_1]);
191         dbg("Offsets - 0th: [%d] 1st: [%d]", nvm_info.m_offset_0, nvm_info.m_offset_1);
192
193         nvm_type = *(data + NVM_FILE_TYPE_POS);
194         if ((NVM_TYPE_CALIB <= nvm_type)
195                         && (NVM_TYPE_DYNAMIC >= nvm_type)) {
196                 dbg("NVM type: [%d]", nvm_type);
197
198                 /* Write NVM data to file */
199                 ret_val = __nvm_write_payload_0(nvm_type, data, &nvm_info);
200         } else {
201                 err("Wrong NVM file type: [%d]", nvm_type);
202                 ret_val = NVM_RES_ERR;
203         }
204
205         return ret_val;
206 }
207
208 gboolean nvm_create_nvm_data()
209 {
210         int modem_fd;
211         int nv_fd;
212         char *buffer = NULL;
213         char err_str[256] = {0, };
214
215         gboolean ret_val = FALSE;
216         dbg("Entered");
217
218         /* Open modem binary */
219         modem_fd = open(MODEM_IMAGE_PATH, O_RDONLY | O_NDELAY);
220         if (modem_fd < 0) {
221                 strerror_r(errno, err_str, 255);
222                 err("[OPEN] Failed for (%s): [%s]", MODEM_IMAGE_PATH, err_str);
223                 return ret_val;
224         }
225
226         /* Create NV data folder if it doesn't exist */
227         if (mkdir(NVM_DIR_PATH, 0755) < 0) {
228                 if (errno != EEXIST) {
229                         strerror_r(errno, err_str, 255);
230                         err("mkdir() failed: [%s]", err_str);
231
232                         /* Close 'modem_fd' */
233                         close(modem_fd);
234                         return ret_val;
235                 } else if ((nv_fd = open(NV_FILE_PATH, O_EXCL)) >= 0) {
236                         /* NV data file already exists */
237                         dbg("File exists: [%s]", NV_FILE_PATH);
238
239                         /* Close 'modem_fd' */
240                         close(modem_fd);
241                         close(nv_fd);
242                         return TRUE;
243                 } else {
244                         dbg("File does't exsits... need to create!!!");
245                 }
246         }
247
248         /* Change directory permissions */
249         if (chmod(NVM_DIR_PATH, 0755) < 0) {
250                 strerror_r(errno, err_str, 255);
251                 err("chmod() failed: [%s]", err_str);
252
253                 /* Close 'modem_fd' */
254                 close(modem_fd);
255                 return ret_val;
256         }
257
258         /* Open NV data file for different file operations */
259         nv_fd = open(NV_FILE_PATH, O_RDWR | O_CREAT | O_SYNC, S_IRWXU);
260         if (nv_fd < 0) {
261                 strerror_r(errno, err_str, 255);
262                 err("[OPEN] Failed for (%s): %s", NV_FILE_PATH, err_str);
263
264                 /* Close 'modem_fd' */
265                 close(modem_fd);
266                 return ret_val;
267         }
268
269         dbg("Setting the file descriptor offset to NV data in modem.bin");
270         do {
271                 /* Seek pre-defined offset in modem binary */
272                 if (lseek(modem_fd, MODEM_NV_OFFSET, SEEK_SET) < 0) {
273                         strerror_r(errno, err_str, 255);
274                         err("[SEEK] Failed: [%s]", err_str);
275                         break;
276                 }
277
278                 /* Allocate memory */
279                 buffer = g_try_malloc0(MAX_NVDATA_SIZE);
280                 if (NULL == buffer) {
281                         err("Failed to allocate memory");
282                         break;
283                 }
284
285                 /* Read NV data from modem binary */
286                 if (read(modem_fd, buffer, MAX_NVDATA_SIZE) < 0) {
287                         strerror_r(errno, err_str, 255);
288                         err("[READ] Failed: [%s]", err_str);
289                         break;
290                 }
291
292                 /* Write the data read from modem binary to nvdata */
293                 if (write(nv_fd, buffer, MAX_NVDATA_SIZE) < 0) {
294                         strerror_r(errno, err_str, 255);
295                         err("[WRITE} Failed: [%s]", err_str);
296                         break;
297                 }
298
299                 ret_val = TRUE;
300         } while (0);
301
302         if (ret_val == FALSE)
303                 err("nvdata (%s) creation Failed!!!", NV_FILE_PATH);
304         else
305                 dbg("nvdata (%s) created Success", NV_FILE_PATH);
306
307         /* Close 'fds' */
308         close(modem_fd);
309         close(nv_fd);
310
311         /* Free 'buffer' */
312         g_free(buffer);
313
314         return ret_val;
315 }