blob: 3dc3c113d86e7467f32e8507da8e16efbda849dc [file] [log] [blame]
rjw1f884582022-01-06 17:20:42 +08001/*
2 * Copyright (c) 2018 MediaTek Inc.
3 *
4 * Permission is hereby granted, free of charge, to any person obtaining
5 * a copy of this software and associated documentation files
6 * (the "Software"), to deal in the Software without restriction,
7 * including without limitation the rights to use, copy, modify, merge,
8 * publish, distribute, sublicense, and/or sell copies of the Software,
9 * and to permit persons to whom the Software is furnished to do so,
10 * subject to the following conditions:
11 *
12 * The above copyright notice and this permission notice shall be
13 * included in all copies or substantial portions of the Software.
14 *
15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
16 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
17 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
18 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
19 * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
20 * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
21 * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
22 */
23
24#include <lib/mempool.h>
25#include <lib/zlib.h>
26#include <malloc.h>
27#include <platform/mtk_wdt.h>
28#include <stdint.h>
29#include <stdio.h>
30#include <stdlib.h>
31#include <string.h>
32#include <string.h>
33
34#include "aee.h"
35#include "kdump.h"
36#include "kdump_sdhc.h"
37#include "lib/cksum.h"
38
39#define BLKSIZE 4096
40#define MAX_CONTINUE 16 // only 1MB memory for lk
41#define EXSPACE (BLKSIZE*MAX_CONTINUE) // Expect continue space
42
43uint64_t lba_marker_time;
44struct __attribute__((__packed__)) marked_block_data {
45 uint32_t lba;
46 uint64_t zero_padding[510];
47 uint64_t timestamp;
48 uint32_t crc;
49} bdata;
50
51struct mrdump_lba_handle {
52 struct mrdump_dev *dumpdev;
53 uint64_t allocsize;
54 uint64_t filesize;
55 unsigned int wlba;
56 unsigned int rlba;
57 int bidx;
58 int midx;
59 unsigned int blknum;
60 unsigned int block_lba[1024];
61 uint8_t data[EXSPACE];
62};
63
64static uint64_t ext4_lba_to_block_offset(uint32_t lba)
65{
66 return (uint64_t)lba * (uint64_t)BLKSIZE;
67}
68
69#ifdef MTK_USERIMAGES_USE_F2FS
70static bool check_block_valid(const struct mrdump_lba_handle *handle, uint32_t lba)
71{
72 mtk_wdt_restart();
73 if (!handle->dumpdev->read(handle->dumpdev, ext4_lba_to_block_offset(lba), (uint8_t *)&bdata, BLKSIZE)) {
74 voprintf_error(" Read BlockData failed\n");
75 return false;
76 }
77
78 if (bdata.lba != lba) {
79 voprintf_error(" Read BlockData LBA failed (c:%08x, v:%08x)\n", bdata.lba, lba);
80 return false;
81 }
82
83 if (bdata.timestamp != lba_marker_time) {
84 voprintf_error(" Read BlockData timestamp failed (c:%016x, v:%016x)\n", bdata.timestamp, lba_marker_time);
85 return false;
86 }
87
88 unsigned int crcval = crc32(0, Z_NULL, 0);
89 crcval = crc32(crcval, (void *)&bdata, (BLKSIZE - 4));
90 if (bdata.crc != crcval) {
91 voprintf_error("%s: Get BlockData crc32 error (c:%08x, v:%08x)\n", __func__, crcval, bdata.crc);
92 return false;
93 }
94
95 return true;
96}
97#endif
98
99static int Get_Next_bidx(struct mrdump_lba_handle *handle, unsigned int moves)
100{
101 unsigned int mycrc;
102
103 if (handle->bidx == 1022) {
104 handle->rlba = handle->block_lba[handle->bidx];
105 if (!handle->dumpdev->read(handle->dumpdev, ext4_lba_to_block_offset(handle->rlba), (uint8_t *)handle->block_lba, BLKSIZE)) {
106 voprintf_error(" SDCard: Reading BlockLBA failed.\n");
107 return -1;
108 }
109 // check crc32
110 mycrc = crc32(0, Z_NULL, 0);
111 mycrc = crc32(mycrc, (void *)handle->block_lba, (BLKSIZE-4));
112 if (mycrc != handle->block_lba[1023]) {
113 voprintf_error(" Get next index crc32 error!\n");
114 return -1;
115 }
116 handle->bidx = 0;
117 } else {
118 handle->bidx+=moves;
119 }
120 return handle->bidx;
121}
122
123unsigned int Num_to_Join(const struct mrdump_lba_handle *handle, unsigned int idx)
124{
125 unsigned int i, j;
126 uint32_t lba;
127
128 for (i=0, j=0; i<MAX_CONTINUE; i++) {
129 lba = handle->block_lba[idx+i];
130 if ((lba - handle->block_lba[idx]) == i) {
131 mtk_wdt_restart();
132#ifdef MTK_USERIMAGES_USE_F2FS
133 if (!check_block_valid(handle, lba)) {
134 voprintf_error(" BlockData Verification failed\n");
135 return 0;
136 }
137#endif
138 j++;
139 continue;
140 }
141 break;
142 }
143 return j;
144}
145
146// Store data and write when buffer(handle's data) full
147// return left length to avoid recursive call. --> turn to for loop
148static int Do_Store_or_Write(struct mrdump_lba_handle *handle, uint8_t *buf, uint32_t Length)
149{
150 int total;
151 unsigned int leftspace, mylen, reval;
152
153 total = BLKSIZE * handle->blknum;
154 leftspace = total - handle->midx;
155
156 // Check Length
157 if (Length > leftspace) {
158 mylen = leftspace;
159 reval = Length - leftspace;
160 } else {
161 mylen = Length;
162 reval = 0;
163 }
164
165 // Store
166 while (mylen > 0) {
167 handle->data[handle->midx] = *buf;
168 handle->midx++;
169 buf++;
170 mylen--;
171 }
172
173 // Write
174 if (handle->midx == total) {
175 if (!handle->dumpdev->write(handle->dumpdev, ext4_lba_to_block_offset(handle->wlba), handle->data, total)) {
176 voprintf_error(" SDCard: Write dump data failed.\n");
177 return -1;
178 }
179 handle->bidx = Get_Next_bidx(handle, handle->blknum);
180 if (handle->bidx < 0) {
181 voprintf_error(" SDCard: Reading bidx failed.\n");
182 return -1;
183 }
184 if (handle->bidx == 1022) {
185 handle->bidx = Get_Next_bidx(handle, handle->blknum);
186 if (handle->bidx < 0) {
187 voprintf_error(" SDCard: Reading 1022 bidx failed.\n");
188 return -1;
189 }
190 }
191 handle->blknum = Num_to_Join(handle, handle->bidx);
192 if (handle->blknum == 0)
193 return -1;
194 handle->wlba = handle->block_lba[handle->bidx];
195 handle->midx = 0;
196 }
197 return reval;
198}
199
200static int lba_write_cb(void *opaque_handle, void *buf, int size)
201{
202 unsigned int len, moves;
203 int ret;
204 uint8_t *Ptr;
205
206 struct mrdump_lba_handle *handle = opaque_handle;
207
208 if ((handle->filesize + size) > handle->allocsize) {
209 voprintf_error(" dump size > allocated size. file-size %lld allocate-size %lld\n", handle->filesize + size, handle->allocsize);
210 return -1;
211 }
212 handle->filesize += size;
213
214 // End of File, write the left Data in handle data buffer...
215 if ((buf == NULL) && (size == 0)) {
216 if (!handle->dumpdev->write(handle->dumpdev, ext4_lba_to_block_offset(handle->wlba), handle->data, handle->midx)) {
217 voprintf_error(" SDCard: Write dump data failed.\n");
218 return -1;
219 }
220 return 0;
221 }
222
223 // buf should not be NULL if not EOF
224 if (buf == NULL)
225 return -1;
226
227 // process of Store and write
228 len = size;
229 ret = len;
230 Ptr = (uint8_t *)buf;
231 while (1) {
232 ret = Do_Store_or_Write(handle, Ptr, len);
233 if (ret < 0) {
234 voprintf_error(" SDCard: Store and Write failed.\n");
235 return -1;
236 } else if (ret==0) {
237 break;
238 } else {
239 moves = len - ret;
240 Ptr += moves;
241 len = ret;
242 }
243 }
244 return size;
245}
246
247static inline uint16_t paf_version_extract(uint8_t pafinfo[MRDUMP_PAF_TOTAL_SIZE])
248{
249 return pafinfo[0] + (pafinfo[1] << 8);
250}
251
252static void dump_paf_info(uint8_t InfoLBA[MRDUMP_PAF_TOTAL_SIZE], const char *msg, ...)
253{
254 va_list ap;
255 va_start(ap, msg);
256 voprintf('E', msg, ap);
257 va_end(ap);
258
259 uint32_t paf_version = paf_version_extract(InfoLBA);
260 uint32_t paf_info_lba = *(uint32_t *)(InfoLBA + MRDUMP_PAF_INFO_LBA);
261 uint32_t paf_addr_lba = *(uint32_t *)(InfoLBA + MRDUMP_PAF_ADDR_LBA);
262 uint64_t paf_alloc_size = *(uint64_t *)(InfoLBA + MRDUMP_PAF_ALLOCSIZE);
263 uint64_t paf_coredump_size = *(uint64_t *)(InfoLBA + MRDUMP_PAF_COREDUMPSIZE);
264 uint64_t paf_timestamp = *(uint64_t *)(InfoLBA + MRDUMP_PAF_TIMESTAMP);
265 uint32_t paf_crc32 = *(uint32_t *)(InfoLBA + MRDUMP_PAF_CRC32);
266
267 voprintf_info(" pafile ver %u info-lba %u addr-lba %u alloc-size %llu coredump-size %llu timestamp %llx crc %x\n",
268 paf_version, paf_info_lba, paf_addr_lba, paf_alloc_size, paf_coredump_size, paf_timestamp, paf_crc32);
269}
270
271int mrdump_ext4_output(const struct mrdump_control_block *mrdump_cb, const struct kzip_addlist *memlist, struct mrdump_dev *mrdump_dev)
272{
273 uint8_t InfoLBA[MRDUMP_PAF_TOTAL_SIZE];
274 unsigned int mycrc;
275
276 if (mrdump_dev == NULL) {
277 return -1;
278 }
279
280 voprintf_info("Output to EXT4 Partition %s\n", mrdump_dev->name);
281
282 // pre-work for ext4 LBA
283 bzero(InfoLBA, sizeof(InfoLBA));
284
285 // Error 1. InfoLBA starting address not available
286 if (mrdump_cb->output_fs_lbaooo == 0) {
287 voprintf_error(" Pre-Allocate has no LBA markers(lbaooo=%u). RAM-Dump stop!\n", mrdump_cb->output_fs_lbaooo);
288 return -1;
289 }
290 if (!mrdump_dev->read(mrdump_dev, ext4_lba_to_block_offset(mrdump_cb->output_fs_lbaooo), (uint8_t *)InfoLBA, sizeof(InfoLBA))) {
291 voprintf_error(" SDCard: Reading InfoLBA failed.\n");
292 return -1;
293 }
294
295 uint32_t paf_version = paf_version_extract(InfoLBA);
296 uint32_t paf_info_lba = *(uint32_t *)(InfoLBA + MRDUMP_PAF_INFO_LBA);
297 uint32_t paf_addr_lba = *(uint32_t *)(InfoLBA + MRDUMP_PAF_ADDR_LBA);
298 uint64_t paf_alloc_size = *(uint64_t *)(InfoLBA + MRDUMP_PAF_ALLOCSIZE);
299 uint64_t paf_coredump_size = *(uint64_t *)(InfoLBA + MRDUMP_PAF_COREDUMPSIZE);
300 uint64_t paf_timestamp = *(uint64_t *)(InfoLBA + MRDUMP_PAF_TIMESTAMP);
301 uint32_t paf_info_crc32 = *(uint32_t *)(InfoLBA + MRDUMP_PAF_CRC32);
302
303 if (paf_version != MRDUMP_PAF_VERSION) {
304 dump_paf_info(InfoLBA, " Unsupport PAF version %d (expected: %d)\n", paf_version, MRDUMP_PAF_VERSION);
305 return -1;
306 }
307 // Error 3. InfoLBA[EXT4_1ST_LBA] should be mrdump_cb->output_fs_lbaooo
308 if (mrdump_cb->output_fs_lbaooo != paf_info_lba) {
309 dump_paf_info(InfoLBA, " LBA Starting Address Error(LBA0=%u)! Abort!\n", paf_info_lba);
310 return -1;
311 }
312
313 // Error 4. EXT4_CORE_DUMP_SIZE is not zero --> want to hold 1st dump
314 if (paf_coredump_size != 0) {
315 dump_paf_info(InfoLBA, " CORE DUMP SIZE is not Zero! Abort!(coresize=%llu)\n", paf_coredump_size);
316 return -1;
317 }
318
319 // Error 5. EXT4_USER_FILESIZE is zero
320 if (paf_alloc_size == 0) {
321 dump_paf_info(InfoLBA, " Allocate file with zero size. Abort!(filesize=%llu)\n", paf_alloc_size);
322 return -1;
323 }
324
325 // get lba_marker_time as timestamp
326 lba_marker_time = paf_timestamp;
327
328 // Error 2. CRC not matched
329 mycrc = crc32(0L, Z_NULL, 0);
330 mycrc = crc32(mycrc, (const unsigned char *)InfoLBA, sizeof(InfoLBA) - 4);
331 if (mycrc != paf_info_crc32) {
332 dump_paf_info(InfoLBA, " InfoLBA CRC32 Error! Abort! (CRC1=0x%08x, CRC2=0x%08x)\n", mycrc, paf_info_crc32);
333 return -1;
334 }
335
336 //struct mrdump_lba_handle *handle = memalign(16, sizeof(struct mrdump_lba_handle));
337 /* return is auto align to CACHE_LINE: which is 64 */
338 struct mrdump_lba_handle *handle = mempool_alloc(sizeof(struct mrdump_lba_handle), MEMPOOL_ANY);
339 if ((handle == NULL) || (((unsigned long long)handle) & 0xf)) {
340 voprintf_error("No enough memory or alloc memory not align 16B\n");
341 return -1;
342 }
343 memset(handle, 0, sizeof(struct mrdump_lba_handle));
344 handle->dumpdev = mrdump_dev;
345 handle->rlba = mrdump_cb->output_fs_lbaooo;
346 handle->allocsize = paf_alloc_size;
347
348 // Starting Dumping Data
349 handle->rlba = paf_addr_lba;
350 if (!handle->dumpdev->read(handle->dumpdev, ext4_lba_to_block_offset(handle->rlba), (uint8_t *)handle->block_lba, BLKSIZE)) {
351 dump_paf_info(InfoLBA, " SDCard: Reading BlockLBA error.\n");
352 mempool_free(handle);
353 return -1;
354 }
355 handle->wlba = handle->block_lba[handle->midx];
356 handle->blknum = Num_to_Join(handle, handle->bidx);
357 if (handle->blknum == 0) {
358 voprintf_error("No continuous space.\n");
359 mempool_free(handle);
360 return -1;
361 }
362
363 voprintf_info(" Pre-Allocate starts at LBA: %u\n", paf_info_lba);
364 voprintf_info(" SYS_COREDUMP starts at LBA: %u\n", handle->wlba);
365
366 mtk_wdt_restart();
367
368 bool ok = true;
369 mtk_wdt_restart();
370
371 struct kzip_file *zf = kzip_open(handle, lba_write_cb);
372 if (zf != NULL) {
373 if (!kzip_add_file(zf, memlist, "SYS_COREDUMP")) {
374 ok = false;
375 }
376 mtk_wdt_restart();
377 kzip_close(zf);
378 lba_write_cb(handle, NULL, 0); /* really write onto emmc of the last part */
379 zf = NULL;
380 } else {
381 ok = false;
382 }
383
384 if (!ok) {
385 mempool_free(handle);
386 return -1;
387 }
388
389 voprintf_info(" SYS_COREDUMP ends at LBA: %u\n", handle->wlba);
390 voprintf_info(" Zip COREDUMP size is: %u\n", handle->filesize);
391
392 // Record File Size...
393 *(uint64_t *)(InfoLBA + MRDUMP_PAF_COREDUMPSIZE) = handle->filesize;
394
395 mycrc = crc32(0L, Z_NULL, 0);
396 *(uint32_t *)(InfoLBA + MRDUMP_PAF_CRC32) = crc32(mycrc, (const unsigned char *)InfoLBA, MRDUMP_LBA_DATAONLY);
397 if (!handle->dumpdev->write(handle->dumpdev, ext4_lba_to_block_offset(paf_info_lba), (uint8_t *)InfoLBA, sizeof(InfoLBA))) {
398 voprintf_error(" SDCard: Write InfoLBA error.\n");
399 mempool_free(handle);
400 return -1;
401 }
402 mempool_free(handle);
403
404 mtk_wdt_restart();
405 mrdump_status_ok("OUTPUT:%s\nMODE:%s\n", "EXT4_DATA", mrdump_mode2string(mrdump_cb->crash_record.reboot_mode));
406 return 0;
407}
408