static int mtd_ipanic_block_read_single(struct mtd_ipanic_data *ctx, loff_t offset) { int rc, len; int index = offset >> ctx->mtd->writesize_shift; if ((index < 0) || (index >= IPANIC_OOPS_BLOCK_COUNT)) { return -EINVAL; } rc = ctx->mtd->_read(ctx->mtd, ctx->blk_offset[index], ctx->mtd->writesize, &len, ctx->bounce); ipanic_block_scramble(ctx->bounce, ctx->mtd->writesize); #if 0 if (rc == -EBADMSG) { xlog_printk(ANDROID_LOG_WARN, IPANIC_LOG_TAG, "Check sum error (ignore)\n"); rc = 0; } #endif if (rc == -EUCLEAN) { xlog_printk(ANDROID_LOG_WARN, IPANIC_LOG_TAG, "ECC Check sum error corrected %lld\n", offset); rc = 0; } if ((rc == 0) && (len != ctx->mtd->writesize)) { xlog_printk(ANDROID_LOG_WARN, IPANIC_LOG_TAG, "aee-ipanic: read size mismatch %d\n", len); return -EINVAL; } return rc; }
char *emmc_allocate_and_read(int offset, int length) { int size; char *buff = NULL; if (length == 0) { return NULL; } size = ALIGN(length, EMMC_BLOCK_SIZE); buff = kzalloc(size, GFP_KERNEL); if (buff != NULL) { if (card_dump_func_read(buff, size, offset, DUMP_INTO_BOOT_CARD_IPANIC) != 0) { xlog_printk(ANDROID_LOG_ERROR, IPANIC_LOG_TAG, "%s: read from IPANIC data failed(offset:%d,size:%d)\n", __FUNCTION__, offset, size); kfree(buff); return NULL; } } else { xlog_printk(ANDROID_LOG_ERROR, IPANIC_LOG_TAG, "%s: Cannot allocate buffer to read(len:%d)\n", __FUNCTION__, length); return NULL; } ipanic_block_scramble(buff, size); return buff; }
void* ipanic_next_write(void* (*next)(void *data, unsigned char *buffer, size_t sz_buf, int *size), void *data, int off, size_t *sz_total) { void* errno = 0; size_t size = 0; unsigned char *ipanic_buffer = emmc_bounce; size_t sz_ipanic_buffer = PAGE_SIZE; errno = next(data, ipanic_buffer, sz_ipanic_buffer, &size); if (IS_ERR(errno)) return errno; for (*sz_total = 0; size != 0; *sz_total += size) { if (off & (EMMC_BLOCK_SIZE - 1)) return ERR_PTR(-2); /*invalid offset, not block aligned*/ ipanic_block_scramble(ipanic_buffer, size); if (size != sz_ipanic_buffer) { memset(ipanic_buffer + size, 0, sz_ipanic_buffer - size); } if (card_dump_func_write(ipanic_buffer, ALIGN(size, EMMC_BLOCK_SIZE), off, DUMP_INTO_BOOT_CARD_IPANIC)) return ERR_PTR(-1); off += size; errno = next(data, ipanic_buffer, sz_ipanic_buffer, &size); if (IS_ERR(errno)) return errno; } return 0; }
void *ipanic_data_from_sd(struct ipanic_data_header *dheader, int encrypt) { void *data; data = ipanic_read_size(dheader->offset, dheader->used); if (data != 0 && encrypt != 0) ipanic_block_scramble((unsigned char *)data, dheader->used); return data; }
inline int ipanic_func_write(fn_next next, void *data, int off, int total, int encrypt) { int errno = 0; size_t size; int start = off; struct ipanic_header *iheader = ipanic_header(); unsigned char *ipanic_buffer = (unsigned char *)(unsigned long)iheader->buf; size_t sz_ipanic_buffer = iheader->bufsize; size_t blksize = iheader->blksize; int many = total > iheader->bufsize; LOGV("off[%x], encrypt[%d]\n", off, encrypt); if (off & (blksize - 1)) return -2; /*invalid offset, not block aligned */ do { errno = next(data, ipanic_buffer, sz_ipanic_buffer); if (IS_ERR(ERR_PTR(errno))) break; size = (size_t) errno; if (size == 0) return (off - start); if ((off - start + size) > total) { LOGE("%s: data oversize(%zx>%x@%x)\n", __func__, off - start + size, total, start); errno = -EFBIG; break; } if (encrypt) ipanic_block_scramble(ipanic_buffer, size); if (size != sz_ipanic_buffer) { memset(ipanic_buffer + size, 0, sz_ipanic_buffer - size); } LOGV("%x@%x\n", size, off); if (ipanic_enable) errno = ipanic_write_size(ipanic_buffer, off, ALIGN(size, blksize)); else errno = -10; if (IS_ERR(ERR_PTR(errno))) break; off += size; if (many == 0) return size; } while (many); return errno; }
static int emmc_ipanic_write(void *buf, int off, int len) { int rem = len & (EMMC_BLOCK_SIZE - 1); len = len & ~(EMMC_BLOCK_SIZE - 1); ipanic_block_scramble(buf, len + rem); if (len > 0) { if (card_dump_func_write((unsigned char *)buf, len, off, EMMC_ID)) return -1; } if (rem != 0) { memcpy(emmc_bounce, buf + len, rem); memset(emmc_bounce + rem, 0, EMMC_BLOCK_SIZE - rem); if (card_dump_func_write(buf, EMMC_BLOCK_SIZE, off + len, EMMC_ID)) return -1; } return len + rem; }
static int mtd_ipanic_block_write(struct mtd_ipanic_data *ctx, loff_t to, int bounce_len) { int rc; size_t wlen; int panic = in_interrupt() | in_atomic(); int index = to >> ctx->mtd->writesize_shift; if ((index < 0) || (index >= IPANIC_OOPS_BLOCK_COUNT)) { return -EINVAL; } if (bounce_len > ctx->mtd->writesize) { xlog_printk(ANDROID_LOG_ERROR, IPANIC_LOG_TAG, "aee-ipanic(%s) len too large\n", __func__); return -EINVAL; } if (panic && !ctx->mtd->_panic_write) { xlog_printk(ANDROID_LOG_ERROR, IPANIC_LOG_TAG, "%s: No panic_write available\n", __func__); return 0; } else if (!panic && !ctx->mtd->_write) { xlog_printk(ANDROID_LOG_ERROR, IPANIC_LOG_TAG, "%s: No write available\n", __func__); return 0; } if (bounce_len < ctx->mtd->writesize) memset(ctx->bounce + bounce_len, 0, ctx->mtd->writesize - bounce_len); ipanic_block_scramble(ctx->bounce, ctx->mtd->writesize); if (panic) rc = ctx->mtd->_panic_write(ctx->mtd, ctx->blk_offset[index], ctx->mtd->writesize, &wlen, ctx->bounce); else rc = ctx->mtd->_write(ctx->mtd, ctx->blk_offset[index], ctx->mtd->writesize, &wlen, ctx->bounce); if (rc) { xlog_printk(ANDROID_LOG_ERROR, IPANIC_LOG_TAG, "%s: Error writing data to flash (%d)\n", __func__, rc); return rc; } return wlen; }
static int ipanic_write_android_buf(unsigned int off, int type) { unsigned int copy_count = 0; while (1) { int rc = panic_dump_android_log(emmc_bounce, PAGE_SIZE, type); BUG_ON(rc < 0); if (rc <= 0) break; if (rc < PAGE_SIZE) { memset(emmc_bounce + rc, 0, PAGE_SIZE - rc); } ipanic_block_scramble(emmc_bounce, PAGE_SIZE); if (card_dump_func_write(emmc_bounce, PAGE_SIZE, off, EMMC_ID)) { xlog_printk(ANDROID_LOG_ERROR, IPANIC_LOG_TAG, "aee-ipanic-emmc(%s): android log %d write failed, offset %d\n", __FUNCTION__, type, off); return -1; } copy_count += rc; off += PAGE_SIZE; } xlog_printk(ANDROID_LOG_DEBUG, IPANIC_LOG_TAG, "%s: dump droid log type %d, count %d\n", __FUNCTION__, type, copy_count); return copy_count; }
static struct aee_oops *emmc_ipanic_oops_copy(void) { struct aee_oops *oops = NULL; struct ipanic_header *hdr = NULL; int hdr_size = ALIGN(sizeof(struct ipanic_header), EMMC_BLOCK_SIZE); hdr = kzalloc(hdr_size, GFP_KERNEL); if (hdr == NULL) { xlog_printk(ANDROID_LOG_ERROR, IPANIC_LOG_TAG, "%s: Cannot allocate ipanic header memory\n", __FUNCTION__); return NULL; } if (card_dump_func_read((unsigned char *)hdr, hdr_size, 0, EMMC_ID) < 0) { xlog_printk(ANDROID_LOG_ERROR, IPANIC_LOG_TAG, "%s: emmc panic log header read failed\n", __func__); return NULL; } ipanic_block_scramble((unsigned char *)hdr, hdr_size); if (ipanic_header_check(hdr) != 0) { return NULL; } oops = aee_oops_create(AE_DEFECT_FATAL, AE_KE, IPANIC_MODULE_TAG); if (oops != NULL) { struct ipanic_oops_header *oops_header = (struct ipanic_oops_header *) emmc_allocate_and_read(hdr->oops_header_offset, hdr->oops_header_length); if (oops_header == NULL) { xlog_printk(ANDROID_LOG_ERROR, IPANIC_LOG_TAG, "%s: Can't read oops header(len:%d)\n", __FUNCTION__, hdr->oops_header_length); goto error_return; } aee_oops_set_process_path(oops, oops_header->process_path); aee_oops_set_backtrace(oops, oops_header->backtrace); kfree(oops_header); if(hdr->oops_detail_length != 0) { oops->detail = emmc_allocate_and_read(hdr->oops_detail_offset, hdr->oops_detail_length); oops->detail_len = hdr->oops_detail_length; }else { #define TMPDETAILSTR "panic detail is empty" oops->detail = kstrdup(TMPDETAILSTR, GFP_KERNEL); oops->detail_len = sizeof TMPDETAILSTR; } if (oops->detail == NULL) { xlog_printk(ANDROID_LOG_ERROR, IPANIC_LOG_TAG, "%s: read detail failed(len: %d)\n", __FUNCTION__, oops->detail_len); goto error_return; } oops->console = emmc_allocate_and_read(hdr->console_offset, hdr->console_length); oops->console_len = hdr->console_length; if (oops->console == NULL) { xlog_printk(ANDROID_LOG_ERROR, IPANIC_LOG_TAG, "%s: read console failed(len: %d)\n", __FUNCTION__, oops->console_len); goto error_return; } /*If panic from kernel context, no user sapce info available. Shouldn't fail*/ if (0 == hdr->userspace_info_length) { oops->userspace_info = NULL; oops->userspace_info_len = 0; } else { oops->userspace_info = emmc_allocate_and_read(hdr->userspace_info_offset, hdr->userspace_info_length); oops->userspace_info_len = hdr->userspace_info_length; if (oops->userspace_info == NULL) { xlog_printk(ANDROID_LOG_ERROR, IPANIC_LOG_TAG, "%s: read usrespace info failed\n", __FUNCTION__); goto error_return; } } oops->android_main = emmc_allocate_and_read(hdr->android_main_offset, hdr->android_main_length); oops->android_main_len = hdr->android_main_length; if (oops->android_main == NULL) { xlog_printk(ANDROID_LOG_ERROR, IPANIC_LOG_TAG, "%s: read android_main failed\n", __FUNCTION__); goto error_return; } oops->android_radio = emmc_allocate_and_read(hdr->android_radio_offset, hdr->android_radio_length); oops->android_radio_len = hdr->android_radio_length; if (oops->android_radio == NULL) { xlog_printk(ANDROID_LOG_ERROR, IPANIC_LOG_TAG, "%s: read android_radio failed\n", __FUNCTION__); goto error_return; } oops->android_system = emmc_allocate_and_read(hdr->android_system_offset, hdr->android_system_length); oops->android_system_len = hdr->android_system_length; if (oops->android_system == NULL) { xlog_printk(ANDROID_LOG_ERROR, IPANIC_LOG_TAG, "%s: read android_system failed\n", __FUNCTION__); goto error_return; } xlog_printk(ANDROID_LOG_DEBUG, IPANIC_LOG_TAG, "ipanic_oops_copy return OK\n"); kfree(hdr); return oops; } else { xlog_printk(ANDROID_LOG_ERROR, IPANIC_LOG_TAG, "%s: kmalloc failed at header\n", __FUNCTION__); kfree(hdr); return NULL; } error_return: kfree(hdr); aee_oops_free(oops); return NULL; }