#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <malloc.h>
#ifdef MTK_GPT_SCHEME_SUPPORT
#include <platform/partition.h>
#else
#include <mt_partition.h>
#endif
#include <mtk_wdt.h>
#include "aee.h"
#include "mrdump_private.h"
#include <efi.h>
#include <pal_log.h>
#include <lib/crc.h>
#include <part_interface.h>
#include <dev/aee_platform_debug.h>
#ifndef min
#define min(x, y) (x < y ? x : y)
#endif
#define BLKSIZE 4096
#define MAX_CONTINUE 16 // only 1MB memory for lk
#define EXSPACE (BLKSIZE*MAX_CONTINUE) // Expect continue space
#define DATA_SIZE_MIN 5368709120 // 5GB
#define BYTE_SIZE_16MB 16777216
/*For gpt update*/
extern part_t *partition;
extern int gpt_partition_table_update(const char *arg, void *data, unsigned sz);
extern int read_gpt(part_t *part);
struct mrdump_part_handle {
struct mrdump_dev *dumpdev;
uint64_t filesize;
uint64_t woffset;
int midx;
uint8_t data[EXSPACE];
};
// Store data and write when buffer(handle's data) full
// return left length to avoid recursive call. --> turn to for loop
static int Do_Store_or_Write(struct mrdump_part_handle *handle, uint8_t *buf, uint32_t Length)
{
unsigned int leftspace, mylen, reval;
leftspace = EXSPACE - handle->midx;
// Check Length
if (Length > leftspace) {
mylen = leftspace;
reval = Length - leftspace;
} else {
mylen = Length;
reval = 0;
}
memcpy(handle->data + handle->midx, buf, mylen);
handle->midx += mylen;
// Write
if (handle->midx == EXSPACE) {
if (!handle->dumpdev->write(handle->dumpdev, handle->woffset, handle->data, EXSPACE)) {
voprintf_error(" SDCard: Write dump data failed.\n");
return -1;
}
handle->woffset = handle->woffset + EXSPACE;
handle->midx = 0;
}
return reval;
}
static int lba_write_cb(void *opaque_handle, void *buf, int size)
{
unsigned int len;
int ret;
uint8_t *Ptr;
struct mrdump_part_handle *handle = opaque_handle;
handle->filesize += size;
// End of File, write the left Data in handle data buffer...
if ((buf == NULL) && (size == 0)) {
if (!handle->dumpdev->write(handle->dumpdev, handle->woffset, handle->data, handle->midx)) {
voprintf_error(" SDCard: Write dump data failed.\n");
return -1;
}
return 0;
}
ASSERT(buf != NULL);
// process of Store and write
len = size;
Ptr = (uint8_t *)buf;
while (1) {
ret = Do_Store_or_Write(handle, Ptr, len);
if (ret < 0) {
return -1;
} else if (ret == 0) {
break;
} else {
Ptr += (len - ret);
len = ret;
}
}
return size;
}
int mrdump_partition_output(const struct mrdump_control_block *mrdump_cb, const struct kzip_addlist *memlist, const struct kzip_addlist *memlist_cmm, struct mrdump_dev *mrdump_dev)
{
uint8_t InfoHeader[MRDUMP_PAF_TOTAL_SIZE];
unsigned int mycrc;
u64 mrdump_total_sect;
part_dev_t *dev = mt_part_get_device();
if (mrdump_dev == NULL) {
voprintf_info("mrdump_dev is NULL\n");
return -1;
}
if (dev == NULL) {
voprintf_info("dev is NULL\n");
return -1;
}
voprintf_info("Output to dynmaic Partition %s\n", mrdump_dev->name);
mrdump_total_sect = partition_get_size_by_name("mrdump") / dev->blkdev->blksz;
if (mrdump_total_sect == (BYTE_SIZE_16MB / dev->blkdev->blksz)) {
voprintf_error("mrdump partition only 16MB\n");
return -1;
}
// pre-work for dynamic partition header
bzero(InfoHeader, sizeof(InfoHeader));
if (!mrdump_dev->read(mrdump_dev, 0ULL, (uint8_t *)InfoHeader, sizeof(InfoHeader))) {
voprintf_error(" SDCard: Reading InfoHeader failed.\n");
return -1;
}
struct mrdump_part_handle *handle = memalign(16, sizeof(struct mrdump_part_handle));
if (handle == NULL) {
voprintf_error("No enough memory.\n");
return -1;
}
memset(handle, 0, sizeof(struct mrdump_part_handle));
handle->dumpdev = mrdump_dev;
// Mark coredump as ULLONG_MAX to verify the unknown interrupt case during dumping data
*(uint64_t *)(InfoHeader + MRDUMP_PAF_COREDUMPSIZE) = ULLONG_MAX;
//calculate the CRC
mycrc = crc32(0L, NULL, 0);
*(uint32_t *)(InfoHeader + MRDUMP_PAF_CRC32) = crc32(mycrc, (const unsigned char*)InfoHeader, MRDUMP_LBA_DATAONLY);
//update the coredump size and CRC
if (!handle->dumpdev->write(handle->dumpdev, 0ULL, (uint8_t *)InfoHeader, sizeof(InfoHeader))) {
voprintf_error(" SDCard: Write InfoHeader error.\n");
free(handle);
return -1;
}
// Starting Dumping Data
handle->woffset = BLKSIZE;
mtk_wdt_restart();
bool ok = true;
mtk_wdt_restart();
struct kzip_file *zf = kzip_open(handle, lba_write_cb);
if (zf != NULL) {
if (!kzip_add_file(zf, memlist, "SYS_COREDUMP")) {
ok = false;
}
if (ok && !kzip_add_file(zf, memlist_cmm, "kernel.cmm")) {
ok = false;
}
mtk_wdt_restart();
kzip_close(zf);
lba_write_cb(handle, NULL, 0); /* really write onto emmc of the last part */
} else {
ok = false;
}
if (!ok) {
free(handle);
return -1;
}
voprintf_info(" Zip COREDUMP size is: %lld\n", handle->filesize);
// Record File Size...
*(uint64_t *)(InfoHeader + MRDUMP_PAF_COREDUMPSIZE) = handle->filesize;
mycrc = crc32(0L, NULL, 0);
*(uint32_t *)(InfoHeader + MRDUMP_PAF_CRC32) = crc32(mycrc, (const unsigned char*)InfoHeader, MRDUMP_LBA_DATAONLY);
if (!handle->dumpdev->write(handle->dumpdev, 0ULL, (uint8_t *)InfoHeader, sizeof(InfoHeader))) {
voprintf_error(" SDCard: Write InfoHeader error.\n");
free(handle);
return -1;
}
free(handle);
mtk_wdt_restart();
mrdump_status_ok("OUTPUT:%s\nMODE:%s\n", "PARTITION_DATA", mrdump_mode2string(mrdump_cb->crash_record.reboot_mode));
return 0;
}
/*
********** Definition of GPT buffer **********
*/
static void w2s(u8 *dst, int dst_max, u16 *src, int src_max)
{
int i = 0;
int len = min(src_max, dst_max - 1);
while (i < len) {
if (!src[i]) {
break;
}
dst[i] = src[i] & 0xFF;
i++;
}
dst[i] = 0;
return;
}
static int read_data(u8 *buf, u32 part_id, u64 lba, u64 size)
{
int err;
part_dev_t *dev;
dev = mt_part_get_device();
if (!dev) {
pal_log_err("%s: read data, err(no dev)\n", __func__);
return 1;
}
err = dev->read(dev, lba * dev->blkdev->blksz, buf, (int)size, part_id);
if (err != (int)size) {
pal_log_err("%s: read data, err(%d)\n", __func__, err);
return err;
}
return 0;
}
static int write_data(u64 lba, u8 *buf, u64 size, u32 part_id)
{
int err;
part_dev_t *dev;
dev = mt_part_get_device();
if (!dev) {
pal_log_err("%s: write data, err(no dev)\n", __func__);
return 1;
}
err = dev->write(dev, buf, lba * dev->blkdev->blksz, (int)size, part_id);
if (err != (int)size) {
pal_log_err("%s: write data, err(%d)\n", __func__, err);
return err;
}
return 0;
}
/*
* method=0 : mean reduce mrdump patition to SIZE_16MB
* method=1 : mean extend mrdump partition to DRAM_SIZE + SIZE_16MB
*/
int mrdump_gpt_resize(int method)
{
int err;
uint8_t data_name[PART_META_INFO_NAMELEN];
uint8_t mrdump_name[PART_META_INFO_NAMELEN];
u32 part_id, gpt_entries_size;
int data_index, mrdump_index;
part_dev_t *dev = mt_part_get_device();
gpt_entry *entries;
u64 total_dump_size = physical_memory_size();
u64 dram_total_sect;
u64 data_total_sect, mrdump_total_sect;
u64 sz;
u8 *data;
if (!dev) {
voprintf_error("%s: dev not found\n", __func__);
return -1;
}
dram_total_sect = total_dump_size / dev->blkdev->blksz;
part_id = dev->blkdev->part_user;
gpt_entries_size = sizeof(gpt_entry) * PART_MAX_COUNT;
sz = dev->blkdev->blksz + gpt_entries_size;
data = (u8 *)malloc(sz);
if (data == NULL) {
voprintf_error("%s: malloc return NULL\n", __func__);
return -1;
}
/* get gpt header + entries */
err = read_data(data, part_id, 1, sz);
if (err || is_gpt_valid(data, 1) != 0) {
err = read_data(data, part_id, last_lba(part_id), sz);
if (err || is_gpt_valid(data, last_lba(part_id)) != 0) {
voprintf_error("%s: read entries(part_id=%d), err(%d)\n",
__func__, part_id, err);
free(data);
return err;
}
}
/* parse pgpt entries */
entries = (gpt_entry *)(data + dev->blkdev->blksz);
mrdump_index = get_gpt_entry_index("mrdump");
if (mrdump_index < 0) {
voprintf_error("%s: Can't get mrdump partition index\n", __func__);
goto fail;
}
w2s(mrdump_name, PART_META_INFO_NAMELEN, entries[mrdump_index].partition_name, GPT_ENTRY_NAME_LEN);
data_index = get_gpt_entry_index("userdata");
if (data_index < 0) {
voprintf_error("%s: Can't get userdata partition index\n", __func__);
goto fail;
}
w2s(data_name, PART_META_INFO_NAMELEN, entries[data_index].partition_name, GPT_ENTRY_NAME_LEN);
/* resize policy
* method = 0
* 1. set mrdump partition to 16MB when it's size !=16MB
and extend data partition
* method = 1
* 1. data total size should be large or equal to DATA_SIZE_MIN
* 2. only do extend when mrdump total size less than DRAM size + 16MB
* 3. must meet 1. and 2. requirement
*/
data_total_sect = partition_get_size_by_name("userdata") / dev->blkdev->blksz;
mrdump_total_sect = partition_get_size_by_name("mrdump") / dev->blkdev->blksz;
if (method == 0) {
if (mrdump_total_sect == (BYTE_SIZE_16MB / dev->blkdev->blksz)) {
voprintf_error("mrdump partition already resized to 16MB\n");
goto fail;
}
if (mrdump_total_sect != dram_total_sect + (BYTE_SIZE_16MB / dev->blkdev->blksz)) {
voprintf_error("Unknown mrdump partition size (0x%llx)\n", mrdump_total_sect);
goto fail;
}
entries[data_index].ending_lba = entries[data_index].ending_lba + dram_total_sect;
entries[mrdump_index].starting_lba = entries[mrdump_index].starting_lba + dram_total_sect;
}
else if (method == 1) {
if ((data_total_sect - dram_total_sect) < (DATA_SIZE_MIN / dev->blkdev->blksz)) {
voprintf_error("mrdump partition can't do resize (0x%llx < 0x%lx)\n",(data_total_sect - dram_total_sect), (DATA_SIZE_MIN / dev->blkdev->blksz));
goto fail;
}
if (mrdump_total_sect >= dram_total_sect + (BYTE_SIZE_16MB / dev->blkdev->blksz)) {
voprintf_error("mrdump partition already resized\n");
goto fail;
}
/* Update data.ending_lba and mrdump.starting_lba */
entries[data_index].ending_lba = entries[data_index].ending_lba - dram_total_sect;
entries[mrdump_index].starting_lba = entries[mrdump_index].starting_lba - dram_total_sect;
}
else {
voprintf_error("unknown mrdump partition resize method (%d)\n", method);
goto fail;
}
/* Update primary and secondary gpt */
err = gpt_partition_table_update("gpt", data, sz);
if (err) {
voprintf_error("gpt_partition_table_update failed\n");
goto fail;
}
/* re-init partition table afster update pmbor, pgpt and sgpt */
read_gpt(partition);
/* erase data partition */
if ((method == 1) && (partition_erase("userdata") < 0)) {
voprintf_error("userdata partition erase failed\n");
}
fail:
/* Free data buffers after using it */
free(data);
return 0;
}
void mrdump_partition_resize(void)
{
if (get_gpt_entry_index("mrdump") != -1) {
pal_log_err("mrdump_partition_resize: start resize mrdump partition\n");
if (mrdump_get_default_output_device() == MRDUMP_DEV_PARTITION)
mrdump_gpt_resize(1);
else
mrdump_gpt_resize(0);
}
else
pal_log_err("%s: mrdump doesn't exist\n", __func__);
}给我讲解一下这个代码
最新发布