Jelajahi Sumber

init mediatek R lk

Signed-off-by: svoboda18 <dev.svoboda18@gmail.com>
svoboda18 2 tahun lalu
melakukan
2d58a75dd5
100 mengubah file dengan 25466 tambahan dan 0 penghapusan
  1. 75 0
      Android.mk
  2. 66 0
      AndroidBoot.mk
  3. 2 0
      CleanSpec.mk
  4. 22 0
      LICENSE
  5. 0 0
      MODULE_LICENSE_BSD
  6. 575 0
      NOTICE
  7. 1442 0
      app/aboot/aboot.c
  8. 97 0
      app/aboot/bootimg.h
  9. 45 0
      app/aboot/devinfo.h
  10. 398 0
      app/aboot/fastboot.c
  11. 51 0
      app/aboot/fastboot.h
  12. 472 0
      app/aboot/recovery.c
  13. 77 0
      app/aboot/recovery.h
  14. 9 0
      app/aboot/rules.mk
  15. 48 0
      app/aboot/sparse_format.h
  16. 72 0
      app/app.c
  17. 121 0
      app/clocktests/clock_tests.c
  18. 6 0
      app/clocktests/rules.mk
  19. 1354 0
      app/mt_boot/aee/KEDump.c
  20. 150 0
      app/mt_boot/aee/KEHeader.h
  21. 708 0
      app/mt_boot/aee/aee.c
  22. 163 0
      app/mt_boot/aee/aee.h
  23. 246 0
      app/mt_boot/aee/armmmu_translate.c
  24. 419 0
      app/mt_boot/aee/mrdump_datafs.c
  25. 548 0
      app/mt_boot/aee/mrdump_dbgscript.c
  26. 150 0
      app/mt_boot/aee/mrdump_dconfig.c
  27. 107 0
      app/mt_boot/aee/mrdump_dummy.c
  28. 478 0
      app/mt_boot/aee/mrdump_elf.c
  29. 298 0
      app/mt_boot/aee/mrdump_elf.h
  30. 175 0
      app/mt_boot/aee/mrdump_key_setup.c
  31. 441 0
      app/mt_boot/aee/mrdump_mpart.c
  32. 67 0
      app/mt_boot/aee/mrdump_null.c
  33. 262 0
      app/mt_boot/aee/mrdump_private.h
  34. 109 0
      app/mt_boot/aee/mrdump_rsvmem.c
  35. 91 0
      app/mt_boot/aee/mrdump_sddev.c
  36. 141 0
      app/mt_boot/aee/mrdump_setup.c
  37. 287 0
      app/mt_boot/aee/mrdump_usb.c
  38. 690 0
      app/mt_boot/aee/mrdump_zip.c
  39. 319 0
      app/mt_boot/aee/platform_debug.c
  40. 594 0
      app/mt_boot/aee/ram_console.c
  41. 63 0
      app/mt_boot/aee/reboot_record.c
  42. 370 0
      app/mt_boot/blockheader.c
  43. 61 0
      app/mt_boot/blockheader.h
  44. 236 0
      app/mt_boot/bootargs.c
  45. 42 0
      app/mt_boot/bootargs.h
  46. 146 0
      app/mt_boot/decompressor.c
  47. 1756 0
      app/mt_boot/dl_commands.c
  48. 24 0
      app/mt_boot/dl_commands.h
  49. 1015 0
      app/mt_boot/fastboot.c
  50. 67 0
      app/mt_boot/fastboot.h
  51. 1025 0
      app/mt_boot/fdt_op.c
  52. 70 0
      app/mt_boot/fdt_op.h
  53. 246 0
      app/mt_boot/iothread.c
  54. 92 0
      app/mt_boot/iothread.h
  55. 2046 0
      app/mt_boot/mt_boot.c
  56. 72 0
      app/mt_boot/mt_boot.h
  57. 82 0
      app/mt_boot/mt_hvc_call.c
  58. 42 0
      app/mt_boot/mt_hvc_call.h
  59. 116 0
      app/mt_boot/mt_secure_call.c
  60. 76 0
      app/mt_boot/mtk_secure_api.h
  61. 68 0
      app/mt_boot/mtransfer/bulk_process.c
  62. 32 0
      app/mt_boot/mtransfer/bulk_process.h
  63. 144 0
      app/mt_boot/mtransfer/bulk_process_nand.c
  64. 315 0
      app/mt_boot/mtransfer/sparse_state_machine.c
  65. 63 0
      app/mt_boot/mtransfer/sparse_state_machine.h
  66. 391 0
      app/mt_boot/mtransfer/sparse_state_machine_nand.c
  67. 62 0
      app/mt_boot/mtransfer/transfer.h
  68. 377 0
      app/mt_boot/mtransfer/transfer_parallel.c
  69. 379 0
      app/mt_boot/odm_mdtbo.c
  70. 125 0
      app/mt_boot/odm_mdtbo.h
  71. 241 0
      app/mt_boot/rules.mk
  72. 69 0
      app/mt_boot/sec_hrid.c
  73. 43 0
      app/mt_boot/sec_hrid.h
  74. 130 0
      app/mt_boot/sec_socid.c
  75. 524 0
      app/mt_boot/sec_unlock.c
  76. 44 0
      app/mt_boot/sec_unlock.h
  77. 48 0
      app/mt_boot/sparse_format.h
  78. 846 0
      app/mt_boot/sys_commands.c
  79. 79 0
      app/mt_boot/sys_commands.h
  80. 220 0
      app/nandwrite/nandwrite.c
  81. 6 0
      app/nandwrite/rules.mk
  82. 249 0
      app/pcitests/pci_tests.c
  83. 6 0
      app/pcitests/rules.mk
  84. 12 0
      app/rules.mk
  85. 7 0
      app/shell/rules.mk
  86. 41 0
      app/shell/shell.c
  87. 169 0
      app/stringtests/mymemcpy.S
  88. 109 0
      app/stringtests/mymemset.S
  89. 6 0
      app/stringtests/rules.mk
  90. 285 0
      app/stringtests/string_tests.c
  91. 30 0
      app/tests/include/app/tests.h
  92. 72 0
      app/tests/led_tests.c
  93. 90 0
      app/tests/printf_tests.c
  94. 8 0
      app/tests/rules.mk
  95. 46 0
      app/tests/tests.c
  96. 322 0
      app/tests/thread_tests.c
  97. 144 0
      arch/arm/arch.c
  98. 98 0
      arch/arm/asm.S
  99. 411 0
      arch/arm/cache-ops.S
  100. 133 0
      arch/arm/cache.c

+ 75 - 0
Android.mk

@@ -0,0 +1,75 @@
+LOCAL_PATH := $(call my-dir)
+LK_ROOT_DIR := $$(pwd)
+LK_CROSS_COMPILE := $(LK_ROOT_DIR)/prebuilts/gcc/linux-x86/arm/arm-linux-androideabi-4.9.1/bin/arm-linux-androideabi-
+
+ifeq ($(strip $(MTK_LK_VERSION)),lk)
+
+ifdef LK_PROJECT
+    LK_DIR := $(LOCAL_PATH)
+
+  ifeq ($(wildcard $(TARGET_PREBUILT_LK)),)
+
+    ifeq ($(LK_CROSS_COMPILE),)
+    ifeq ($(TARGET_ARCH), arm)
+      LK_CROSS_COMPILE := $(LK_ROOT_DIR)/$(TARGET_TOOLS_PREFIX)
+    else ifeq ($(TARGET_2ND_ARCH), arm)
+      LK_CROSS_COMPILE := $(LK_ROOT_DIR)/$($(TARGET_2ND_ARCH_VAR_PREFIX)TARGET_TOOLS_PREFIX)
+    endif
+    endif
+
+    LK_MAKE_DEPENDENCIES := $(shell find $(LK_DIR) -name .git -prune -o -type f | sort)
+    LK_MAKE_DEPENDENCIES := $(filter-out %/.git %/.gitignore %/.gitattributes,$(LK_MAKE_DEPENDENCIES))
+
+    LK_MODE :=
+    include $(LOCAL_PATH)/build_lk.mk
+
+    ifeq (yes,$(BOARD_BUILD_SBOOT_DIS))
+      LK_MODE := _DEF_UNLOCK
+      include $(LOCAL_PATH)/build_lk.mk
+    endif
+
+    ifeq (yes,$(BOARD_BUILD_ENHANCE_MENU))
+      LK_MODE := _ENHANCE_MENU
+      include $(LOCAL_PATH)/build_lk.mk
+    endif
+
+    ifeq (yes,$(BOARD_DEEP_GPT_UPDATE))
+      LK_MODE := _DEEP_GPT_UPDATE
+      include $(LOCAL_PATH)/build_lk.mk
+    endif
+
+    LK_MODE := _FES
+    include $(LOCAL_PATH)/build_lk.mk
+
+.PHONY: lk check-lk-config check-mtk-config
+droid lk: check-lk-config
+check-mtk-config: check-lk-config
+check-lk-config:
+ifneq (yes,$(strip $(DISABLE_MTK_CONFIG_CHECK)))
+	python device/mediatek/build/build/tools/check_kernel_config.py -c $(MTK_TARGET_PROJECT_FOLDER)/ProjectConfig.mk -l $(LK_DIR)/project/$(LK_PROJECT).mk -p $(MTK_PROJECT_NAME)
+else
+	-python device/mediatek/build/build/tools/check_kernel_config.py -c $(MTK_TARGET_PROJECT_FOLDER)/ProjectConfig.mk -l $(LK_DIR)/project/$(LK_PROJECT).mk -p $(MTK_PROJECT_NAME)
+endif
+
+  else
+
+    INSTALLED_LK_TARGET := $(PRODUCT_OUT)/lk.img
+    INSTALLED_LOGO_TARGET := $(PRODUCT_OUT)/logo.bin
+
+
+$(INSTALLED_LK_TARGET): $(TARGET_PREBUILT_LK) $(MTK_LK_DTB_TARGET)
+	$(hide) mkdir -p $(dir $@)
+	$(hide) cat $^ > $@
+
+$(INSTALLED_LOGO_TARGET): $(dir $(TARGET_PREBUILT_LK))$(notdir $(INSTALLED_LOGO_TARGET))
+	$(hide) mkdir -p $(dir $@)
+	$(hide) cp -f $< $@
+
+.PHONY: lk
+droidcore lk: $(INSTALLED_LK_TARGET) $(INSTALLED_LOGO_TARGET)
+
+  endif#TARGET_PREBUILT_LK
+
+endif#LK_PROJECT
+
+endif#MTK_LK_VERSION

+ 66 - 0
AndroidBoot.mk

@@ -0,0 +1,66 @@
+#Android makefile to build lk bootloader as a part of Android Build
+
+ifeq ($(call is-android-codename,HONEYCOMB),true)
+CROSS_TOOL := ../../../prebuilt/linux-x86/toolchain/arm-eabi-4.4.3/bin/arm-eabi-
+else ifeq ($(call is-android-codename,ICECREAM_SANDWICH),true)
+CROSS_TOOL := ../../../prebuilt/linux-x86/toolchain/arm-eabi-4.4.3/bin/arm-eabi-
+else
+CROSS_TOOL := ../../../prebuilt/linux-x86/toolchain/arm-eabi-4.4.0/bin/arm-eabi-
+endif
+
+# Set flags if we need to include security libs
+ifeq ($(TARGET_BOOTIMG_SIGNED),true)
+  SIGNED_KERNEL := SIGNED_KERNEL=1
+else
+  SIGNED_KERNEL := SIGNED_KERNEL=0
+endif
+
+# NAND variant output
+TARGET_NAND_BOOTLOADER := $(PRODUCT_OUT)/appsboot.mbn
+NAND_BOOTLOADER_OUT := $(TARGET_OUT_INTERMEDIATES)/NAND_BOOTLOADER_OBJ
+
+# Remove bootloader binary to trigger recompile when source changes
+appsbootldr_clean:
+	$(hide) rm -f $(TARGET_NAND_BOOTLOADER)
+
+$(NAND_BOOTLOADER_OUT):
+	mkdir -p $(NAND_BOOTLOADER_OUT)
+
+# eMMC variant output
+TARGET_EMMC_BOOTLOADER := $(PRODUCT_OUT)/emmc_appsboot.mbn
+EMMC_BOOTLOADER_OUT := $(TARGET_OUT_INTERMEDIATES)/EMMC_BOOTLOADER_OBJ
+
+emmc_appsbootldr_clean:
+	$(hide) rm -f $(TARGET_EMMC_BOOTLOADER)
+
+$(EMMC_BOOTLOADER_OUT):
+	mkdir -p $(EMMC_BOOTLOADER_OUT)
+
+# Top level for NAND variant targets
+$(TARGET_NAND_BOOTLOADER): appsbootldr_clean | $(NAND_BOOTLOADER_OUT)
+	$(MAKE) -C vendor/mediatek/proprietary/bootable/bootloader/lk TOOLCHAIN_PREFIX=$(CROSS_TOOL) BOOTLOADER_OUT=../../../$(NAND_BOOTLOADER_OUT) $(TARGET_PRODUCT) $(SIGNED_KERNEL)
+
+# Top level for eMMC variant targets
+$(TARGET_EMMC_BOOTLOADER): emmc_appsbootldr_clean | $(EMMC_BOOTLOADER_OUT)
+	$(MAKE) -C vendor/mediatek/proprietary/bootable/bootloader/lk TOOLCHAIN_PREFIX=$(CROSS_TOOL) BOOTLOADER_OUT=../../../$(EMMC_BOOTLOADER_OUT) $(TARGET_PRODUCT) EMMC_BOOT=1 $(SIGNED_KERNEL)
+
+# Keep build NAND & eMMC as default for targets still using TARGET_BOOTLOADER
+TARGET_BOOTLOADER := $(PRODUCT_OUT)/EMMCBOOT.MBN
+$(TARGET_BOOTLOADER): $(NAND_BOOTLOADER_OUT) $(EMMC_BOOTLOADER_OUT) | $(TARGET_NAND_BOOTLOADER) $(TARGET_EMMC_BOOTLOADER)
+
+#
+# Build nandwrite as a part of Android Build for NAND configurations
+#
+TARGET_NANDWRITE := $(PRODUCT_OUT)/obj/nandwrite/build-$(TARGET_PRODUCT)_nandwrite/lk
+NANDWRITE_OUT := $(TARGET_OUT_INTERMEDIATES)/nandwrite
+
+nandwrite_clean:
+	$(hide) rm -f $(TARGET_NANDWRITE)
+	$(hide) rm -rf $(NANDWRITE_OUT)
+
+$(NANDWRITE_OUT):
+	mkdir -p $(NANDWRITE_OUT)
+
+$(TARGET_NANDWRITE): nandwrite_clean | $(NANDWRITE_OUT)
+	@echo $(TARGET_PRODUCT)_nandwrite
+	$(MAKE) -C vendor/mediatek/proprietary/bootable/bootloader/lk TOOLCHAIN_PREFIX=$(CROSS_TOOL) BOOTLOADER_OUT=../../../$(NANDWRITE_OUT) $(TARGET_PRODUCT)_nandwrite BUILD_NANDWRITE=1

+ 2 - 0
CleanSpec.mk

@@ -0,0 +1,2 @@
+# Copyright (c) 2015 MediaTek Inc.
+# dummy file

+ 22 - 0
LICENSE

@@ -0,0 +1,22 @@
+/*
+ * Copyright (c) 2008-2010 Travis Geiselbrecht
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files
+ * (the "Software"), to deal in the Software without restriction,
+ * including without limitation the rights to use, copy, modify, merge,
+ * publish, distribute, sublicense, and/or sell copies of the Software,
+ * and to permit persons to whom the Software is furnished to do so,
+ * subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+ * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */

+ 0 - 0
MODULE_LICENSE_BSD


+ 575 - 0
NOTICE

@@ -0,0 +1,575 @@
+This MediaTek software package contains software with the following notices and under the following licenses:
+
+==============================================================================================================
+
+Copyright (C) 2016 The Android Open Source Project
+Copyright (C) 1995-2005 Jean-loup Gailly.
+Copyright (C) 1995-2005 Mark Adler
+Copyright (c) 2015 Oleksandr Tymoshenko <gonzo@FreeBSD.org>
+
+                                 Apache License
+                           Version 2.0, January 2004
+                        http://www.apache.org/licenses/
+
+   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+   1. Definitions.
+
+      "License" shall mean the terms and conditions for use, reproduction,
+      and distribution as defined by Sections 1 through 9 of this document.
+
+      "Licensor" shall mean the copyright owner or entity authorized by
+      the copyright owner that is granting the License.
+
+      "Legal Entity" shall mean the union of the acting entity and all
+      other entities that control, are controlled by, or are under common
+      control with that entity. For the purposes of this definition,
+      "control" means (i) the power, direct or indirect, to cause the
+      direction or management of such entity, whether by contract or
+      otherwise, or (ii) ownership of fifty percent (50%) or more of the
+      outstanding shares, or (iii) beneficial ownership of such entity.
+
+      "You" (or "Your") shall mean an individual or Legal Entity
+      exercising permissions granted by this License.
+
+      "Source" form shall mean the preferred form for making modifications,
+      including but not limited to software source code, documentation
+      source, and configuration files.
+
+      "Object" form shall mean any form resulting from mechanical
+      transformation or translation of a Source form, including but
+      not limited to compiled object code, generated documentation,
+      and conversions to other media types.
+
+      "Work" shall mean the work of authorship, whether in Source or
+      Object form, made available under the License, as indicated by a
+      copyright notice that is included in or attached to the work
+      (an example is provided in the Appendix below).
+
+      "Derivative Works" shall mean any work, whether in Source or Object
+      form, that is based on (or derived from) the Work and for which the
+      editorial revisions, annotations, elaborations, or other modifications
+      represent, as a whole, an original work of authorship. For the purposes
+      of this License, Derivative Works shall not include works that remain
+      separable from, or merely link (or bind by name) to the interfaces of,
+      the Work and Derivative Works thereof.
+
+      "Contribution" shall mean any work of authorship, including
+      the original version of the Work and any modifications or additions
+      to that Work or Derivative Works thereof, that is intentionally
+      submitted to Licensor for inclusion in the Work by the copyright owner
+      or by an individual or Legal Entity authorized to submit on behalf of
+      the copyright owner. For the purposes of this definition, "submitted"
+      means any form of electronic, verbal, or written communication sent
+      to the Licensor or its representatives, including but not limited to
+      communication on electronic mailing lists, source code control systems,
+      and issue tracking systems that are managed by, or on behalf of, the
+      Licensor for the purpose of discussing and improving the Work, but
+      excluding communication that is conspicuously marked or otherwise
+      designated in writing by the copyright owner as "Not a Contribution."
+
+      "Contributor" shall mean Licensor and any individual or Legal Entity
+      on behalf of whom a Contribution has been received by Licensor and
+      subsequently incorporated within the Work.
+
+   2. Grant of Copyright License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      copyright license to reproduce, prepare Derivative Works of,
+      publicly display, publicly perform, sublicense, and distribute the
+      Work and such Derivative Works in Source or Object form.
+
+   3. Grant of Patent License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      (except as stated in this section) patent license to make, have made,
+      use, offer to sell, sell, import, and otherwise transfer the Work,
+      where such license applies only to those patent claims licensable
+      by such Contributor that are necessarily infringed by their
+      Contribution(s) alone or by combination of their Contribution(s)
+      with the Work to which such Contribution(s) was submitted. If You
+      institute patent litigation against any entity (including a
+      cross-claim or counterclaim in a lawsuit) alleging that the Work
+      or a Contribution incorporated within the Work constitutes direct
+      or contributory patent infringement, then any patent licenses
+      granted to You under this License for that Work shall terminate
+      as of the date such litigation is filed.
+
+   4. Redistribution. You may reproduce and distribute copies of the
+      Work or Derivative Works thereof in any medium, with or without
+      modifications, and in Source or Object form, provided that You
+      meet the following conditions:
+
+      (a) You must give any other recipients of the Work or
+          Derivative Works a copy of this License; and
+
+      (b) You must cause any modified files to carry prominent notices
+          stating that You changed the files; and
+
+      (c) You must retain, in the Source form of any Derivative Works
+          that You distribute, all copyright, patent, trademark, and
+          attribution notices from the Source form of the Work,
+          excluding those notices that do not pertain to any part of
+          the Derivative Works; and
+
+      (d) If the Work includes a "NOTICE" text file as part of its
+          distribution, then any Derivative Works that You distribute must
+          include a readable copy of the attribution notices contained
+          within such NOTICE file, excluding those notices that do not
+          pertain to any part of the Derivative Works, in at least one
+          of the following places: within a NOTICE text file distributed
+          as part of the Derivative Works; within the Source form or
+          documentation, if provided along with the Derivative Works; or,
+          within a display generated by the Derivative Works, if and
+          wherever such third-party notices normally appear. The contents
+          of the NOTICE file are for informational purposes only and
+          do not modify the License. You may add Your own attribution
+          notices within Derivative Works that You distribute, alongside
+          or as an addendum to the NOTICE text from the Work, provided
+          that such additional attribution notices cannot be construed
+          as modifying the License.
+
+      You may add Your own copyright statement to Your modifications and
+      may provide additional or different license terms and conditions
+      for use, reproduction, or distribution of Your modifications, or
+      for any such Derivative Works as a whole, provided Your use,
+      reproduction, and distribution of the Work otherwise complies with
+      the conditions stated in this License.
+
+   5. Submission of Contributions. Unless You explicitly state otherwise,
+      any Contribution intentionally submitted for inclusion in the Work
+      by You to the Licensor shall be under the terms and conditions of
+      this License, without any additional terms or conditions.
+      Notwithstanding the above, nothing herein shall supersede or modify
+      the terms of any separate license agreement you may have executed
+      with Licensor regarding such Contributions.
+
+   6. Trademarks. This License does not grant permission to use the trade
+      names, trademarks, service marks, or product names of the Licensor,
+      except as required for reasonable and customary use in describing the
+      origin of the Work and reproducing the content of the NOTICE file.
+
+   7. Disclaimer of Warranty. Unless required by applicable law or
+      agreed to in writing, Licensor provides the Work (and each
+      Contributor provides its Contributions) on an "AS IS" BASIS,
+      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+      implied, including, without limitation, any warranties or conditions
+      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+      PARTICULAR PURPOSE. You are solely responsible for determining the
+      appropriateness of using or redistributing the Work and assume any
+      risks associated with Your exercise of permissions under this License.
+
+   8. Limitation of Liability. In no event and under no legal theory,
+      whether in tort (including negligence), contract, or otherwise,
+      unless required by applicable law (such as deliberate and grossly
+      negligent acts) or agreed to in writing, shall any Contributor be
+      liable to You for damages, including any direct, indirect, special,
+      incidental, or consequential damages of any character arising as a
+      result of this License or out of the use or inability to use the
+      Work (including but not limited to damages for loss of goodwill,
+      work stoppage, computer failure or malfunction, or any and all
+      other commercial damages or losses), even if such Contributor
+      has been advised of the possibility of such damages.
+
+   9. Accepting Warranty or Additional Liability. While redistributing
+      the Work or Derivative Works thereof, You may choose to offer,
+      and charge a fee for, acceptance of support, warranty, indemnity,
+      or other liability obligations and/or rights consistent with this
+      License. However, in accepting such obligations, You may act only
+      on Your own behalf and on Your sole responsibility, not on behalf
+      of any other Contributor, and only if You agree to indemnify,
+      defend, and hold each Contributor harmless for any liability
+      incurred by, or claims asserted against, such Contributor by reason
+      of your accepting any such warranty or additional liability.
+
+   END OF TERMS AND CONDITIONS
+
+
+
+
+Copyright (C) 1995-2005 Mark Adler
+Copyright (C) 2006 David Gibson, IBM Corporation.
+Copyright (C) 1995-2005 Jean-loup Gailly
+Copyright (C) 1995-2004 Mark Adler
+Copyright (C) 1995-2005 Jean-loup Gailly.
+Copyright (C) 2012 David Gibson, IBM Corporation.
+Copyright (C) 2014 David Gibson <david@gibson.dropbear.id.au>
+Copyright (C) 1995-2005 Jean-loup Gailly and Mark Adler
+
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without modification, are permitted provided that the
+following conditions are met:
+
+    * Redistributions of source code must retain the above copyright notice, this list of conditions and the following
+disclaimer.
+    * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the
+following disclaimer in the documentation and/or other materials provided with the distribution.
+    * Neither the name of the <ORGANIZATION> nor the names of its contributors may be used to endorse or promote
+products derived from this software without specific prior written permission.
+
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
+INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+
+
+
+
+Copyright (C) 1995-2004 Mark Adler
+Copyright (C) 2006 David Gibson, IBM Corporation.
+
+BSD Two Clause License
+
+Redistribution and use in source and binary forms, with or without modification, are permitted provided that the
+following conditions are met:
+
+   1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following
+disclaimer.
+   2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the
+following disclaimer in the documentation and/or other materials provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE AUTHOR "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+
+
+
+Copyright (C) 2017 The Android Open Source Project
+Copyright 2007, The Android Open Source Project
+Copyright (c) 2008 Travis Geiselbrecht
+
+This is the Android Software Development Kit License Agreement.
+
+1. Introduction
+
+1.1 The Android Software Development Kit (referred to in this License Agreement as the "SDK" and specifically including
+the Android system files, packaged APIs, and Google APIs add-ons) is licensed to you subject to the terms of this
+License Agreement. This License Agreement forms a legally binding contract between you and Google in relation to your
+use of the SDK.
+
+1.2 "Google" means Google Inc., a Delaware corporation with principal place of business at 1600 Amphitheatre Parkway,
+Mountain View, CA 94043, United States.
+
+2. Accepting this License Agreement
+
+2.1 In order to use the SDK, you must first agree to this License Agreement. You may not use the SDK if you do not
+accept this License Agreement.
+
+2.2 You can accept this License Agreement by:
+
+(A) clicking to accept or agree to this License Agreement, where this option is made available to you; or
+
+(B) by actually using the SDK. In this case, you agree that use of the SDK constitutes acceptance of the Licensing
+Agreement from that point onwards.
+
+2.3 You may not use the SDK and may not accept the Licensing Agreement if you are a person barred from receiving the SDK
+under the laws of the United States or other countries including the country in which you are resident or from which you
+use the SDK.
+
+2.4 If you are agreeing to be bound by this License Agreement on behalf of your employer or other entity, you represent
+and warrant that you have full legal authority to bind your employer or such entity to this License Agreement. If you do
+not have the requisite authority, you may not accept the Licensing Agreement or use the SDK on behalf of your employer
+or other entity.
+
+3. SDK License from Google
+
+3.1 Subject to the terms of this License Agreement, Google grants you a limited, worldwide, royalty-free, non-
+assignable and non-exclusive license to use the SDK solely to develop applications to run on the Android platform.
+
+3.2 You agree that Google or third parties own all legal right, title and interest in and to the SDK, including any
+Intellectual Property Rights that subsist in the SDK. "Intellectual Property Rights" means any and all rights under
+patent law, copyright law, trade secret law, trademark law, and any and all other proprietary rights. Google reserves
+all rights not expressly granted to you.
+
+3.3 Except to the extent required by applicable third party licenses, you may not copy (except for backup purposes),
+modify, adapt, redistribute, decompile, reverse engineer, disassemble, or create derivative works of the SDK or any part
+of the SDK. Except to the extent required by applicable third party licenses, you may not load any part of the SDK onto
+a mobile handset or any other hardware device except a personal computer, combine any part of the SDK with other
+software, or distribute any software or device incorporating a part of the SDK.
+
+3.4 Use, reproduction and distribution of components of the SDK licensed under an open source software license are
+governed solely by the terms of that open source software license and not this License Agreement.
+
+3.5 You agree that the form and nature of the SDK that Google provides may change without prior notice to you and that
+future versions of the SDK may be incompatible with applications developed on previous versions of the SDK. You agree
+that Google may stop (permanently or temporarily) providing the SDK (or any features within the SDK) to you or to users
+generally at Google's sole discretion, without prior notice to you.
+
+3.6 Nothing in this License Agreement gives you a right to use any of Google's trade names, trademarks, service marks,
+logos, domain names, or other distinctive brand features.
+
+3.7 You agree that you will not remove, obscure, or alter any proprietary rights notices (including copyright and
+trademark notices) that may be affixed to or contained within the SDK.
+
+4. Use of the SDK by You
+
+4.1 Google agrees that it obtains no right, title or interest from you (or your licensors) under this License Agreement
+in or to any software applications that you develop using the SDK, including any intellectual property rights that
+subsist in those applications.
+
+4.2 You agree to use the SDK and write applications only for purposes that are permitted by (a) this License Agreement
+and (b) any applicable law, regulation or generally accepted practices or guidelines in the relevant jurisdictions
+(including any laws regarding the export of data or software to and from the United States or other relevant countries).
+
+4.3 You agree that if you use the SDK to develop applications for general public users, you will protect the privacy and
+legal rights of those users. If the users provide you with user names, passwords, or other login information or personal
+information, your must make the users aware that the information will be available to your application, and you must
+provide legally adequate privacy notice and protection for those users. If your application stores personal or sensitive
+information provided by users, it must do so securely. If the user provides your application with Google Account
+information, your application may only use that information to access the user's Google Account when, and for the
+limited purposes for which, the user has given you permission to do so.
+
+4.4 You agree that you will not engage in any activity with the SDK, including the development or distribution of an
+application, that interferes with, disrupts, damages, or accesses in an unauthorized manner the servers, networks, or
+other properties or services of any third party including, but not limited to, Google or any mobile communications
+carrier.
+
+4.5 You agree that you are solely responsible for (and that Google has no responsibility to you or to any third party
+for) any data, content, or resources that you create, transmit or display through the Android platform and/or
+applications for the Android platform, and for the consequences of your actions (including any loss or damage which
+Google may suffer) by doing so.
+
+4.6 You agree that you are solely responsible for (and that Google has no responsibility to you or to any third party
+for) any breach of your obligations under this License Agreement, any applicable third party contract or Terms of
+Service, or any applicable law or regulation, and for the consequences (including any loss or damage which Google or any
+third party may suffer) of any such breach.
+
+5. Your Developer Credentials
+
+5.1 You agree that you are responsible for maintaining the confidentiality of any developer credentials that may be
+issued to you by Google or which you may choose yourself and that you will be solely responsible for all applications
+that are developed under your developer credentials.
+
+6. Privacy and Information
+
+6.1 In order to continually innovate and improve the SDK, Google may collect certain usage statistics from the software
+including but not limited to a unique identifier, associated IP address, version number of the software, and information
+on which tools and/or services in the SDK are being used and how they are being used. Before any of this information is
+collected, the SDK will notify you and seek your consent. If you withhold consent, the information will not be
+collected.
+
+6.2 The data collected is examined in the aggregate to improve the SDK and is maintained in accordance with Google's
+Privacy Policy.
+
+7. Third Party Applications for the Android Platform
+
+7.1 If you use the SDK to run applications developed by a third party or that access data, content or resources provided
+by a third party, you agree that Google is not responsible for those applications, data, content, or resources. You
+understand that all data, content or resources which you may access through such third party applications are the sole
+responsibility of the person from which they originated and that Google is not liable for any loss or damage that you
+may experience as a result of the use or access of any of those third party applications, data, content, or resources.
+
+7.2 You should be aware the data, content, and resources presented to you through such a third party application may be
+protected by intellectual property rights which are owned by the providers (or by other persons or companies on their
+behalf). You may not modify, rent, lease, loan, sell, distribute or create derivative works based on these data,
+content, or resources (either in whole or in part) unless you have been specifically given permission to do so by the
+relevant owners.
+
+7.3 You acknowledge that your use of such third party applications, data, content, or resources may be subject to
+separate terms between you and the relevant third party. In that case, this License Agreement does not affect your legal
+relationship with these third parties.
+
+8. Using Android APIs
+
+8.1 Google Data APIs
+
+8.1.1 If you use any API to retrieve data from Google, you acknowledge that the data may be protected by intellectual
+property rights which are owned by Google or those parties that provide the data (or by other persons or companies on
+their behalf). Your use of any such API may be subject to additional Terms of Service. You may not modify, rent, lease,
+loan, sell, distribute or create derivative works based on this data (either in whole or in part) unless allowed by the
+relevant Terms of Service.
+
+8.1.2 If you use any API to retrieve a user's data from Google, you acknowledge and agree that you shall retrieve data
+only with the user's explicit consent and only when, and for the limited purposes for which, the user has given you
+permission to do so.
+
+9. Terminating this License Agreement
+
+9.1 This License Agreement will continue to apply until terminated by either you or Google as set out below.
+
+9.2 If you want to terminate this License Agreement, you may do so by ceasing your use of the SDK and any relevant
+developer credentials.
+
+9.3 Google may at any time, terminate this License Agreement with you if:
+
+(A) you have breached any provision of this License Agreement; or
+
+(B) Google is required to do so by law; or
+
+(C) the partner with whom Google offered certain parts of SDK (such as APIs) to you has terminated its relationship with
+Google or ceased to offer certain parts of the SDK to you; or
+
+(D) Google decides to no longer providing the SDK or certain parts of the SDK to users in the country in which you are
+resident or from which you use the service, or the provision of the SDK or certain SDK services to you by Google is, in
+Google's sole discretion, no longer commercially viable.
+
+9.4 When this License Agreement comes to an end, all of the legal rights, obligations and liabilities that you and
+Google have benefited from, been subject to (or which have accrued over time whilst this License Agreement has been in
+force) or which are expressed to continue indefinitely, shall be unaffected by this cessation, and the provisions of
+paragraph 14.7 shall continue to apply to such rights, obligations and liabilities indefinitely.
+
+10. DISCLAIMER OF WARRANTIES
+
+10.1 YOU EXPRESSLY UNDERSTAND AND AGREE THAT YOUR USE OF THE SDK IS AT YOUR SOLE RISK AND THAT THE SDK IS PROVIDED "AS
+IS" AND "AS AVAILABLE" WITHOUT WARRANTY OF ANY KIND FROM GOOGLE.
+
+10.2 YOUR USE OF THE SDK AND ANY MATERIAL DOWNLOADED OR OTHERWISE OBTAINED THROUGH THE USE OF THE SDK IS AT YOUR OWN
+DISCRETION AND RISK AND YOU ARE SOLELY RESPONSIBLE FOR ANY DAMAGE TO YOUR COMPUTER SYSTEM OR OTHER DEVICE OR LOSS OF
+DATA THAT RESULTS FROM SUCH USE.
+
+10.3 GOOGLE FURTHER EXPRESSLY DISCLAIMS ALL WARRANTIES AND CONDITIONS OF ANY KIND, WHETHER EXPRESS OR IMPLIED,
+INCLUDING, BUT NOT LIMITED TO THE IMPLIED WARRANTIES AND CONDITIONS OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE
+AND NON-INFRINGEMENT.
+
+11. LIMITATION OF LIABILITY
+
+11.1 YOU EXPRESSLY UNDERSTAND AND AGREE THAT GOOGLE, ITS SUBSIDIARIES AND AFFILIATES, AND ITS LICENSORS SHALL NOT BE
+LIABLE TO YOU UNDER ANY THEORY OF LIABILITY FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL CONSEQUENTIAL OR EXEMPLARY
+DAMAGES THAT MAY BE INCURRED BY YOU, INCLUDING ANY LOSS OF DATA, WHETHER OR NOT GOOGLE OR ITS REPRESENTATIVES HAVE BEEN
+ADVISED OF OR SHOULD HAVE BEEN AWARE OF THE POSSIBILITY OF ANY SUCH LOSSES ARISING.
+
+12. Indemnification
+
+12.1 To the maximum extent permitted by law, you agree to defend, indemnify and hold harmless Google, its affiliates and
+their respective directors, officers, employees and agents from and against any and all claims, actions, suits or
+proceedings, as well as any and all losses, liabilities, damages, costs and expenses (including reasonable attorneys
+fees) arising out of or accruing from (a) your use of the SDK, (b) any application you develop on the SDK that infringes
+any copyright, trademark, trade secret, trade dress, patent or other intellectual property right of any person or
+defames any person or violates their rights of publicity or privacy, and (c) any non-compliance by you with this License
+Agreement.
+
+13. Changes to the License Agreement
+
+13.1 Google may make changes to the License Agreement as it distributes new versions of the SDK. When these changes are
+made, Google will make a new version of the License Agreement available on the website where the SDK is made available.
+
+14. General Legal Terms
+
+14.1 This License Agreement constitute the whole legal agreement between you and Google and govern your use of the SDK
+(excluding any services which Google may provide to you under a separate written agreement), and completely replace any
+prior agreements between you and Google in relation to the SDK.
+
+14.2 You agree that if Google does not exercise or enforce any legal right or remedy which is contained in this License
+Agreement (or which Google has the benefit of under any applicable law), this will not be taken to be a formal waiver of
+Google's rights and that those rights or remedies will still be available to Google.
+
+14.3 If any court of law, having the jurisdiction to decide on this matter, rules that any provision of this License
+Agreement is invalid, then that provision will be removed from this License Agreement without affecting the rest of this
+License Agreement. The remaining provisions of this License Agreement will continue to be valid and enforceable.
+
+14.4 You acknowledge and agree that each member of the group of companies of which Google is the parent shall be third
+party beneficiaries to this License Agreement and that such other companies shall be entitled to directly enforce, and
+rely upon, any provision of this License Agreement that confers a benefit on (or rights in favor of) them. Other than
+this, no other person or company shall be third party beneficiaries to this License Agreement.
+
+14.5 EXPORT RESTRICTIONS. THE SDK IS SUBJECT TO UNITED STATES EXPORT LAWS AND REGULATIONS. YOU MUST COMPLY WITH ALL
+DOMESTIC AND INTERNATIONAL EXPORT LAWS AND REGULATIONS THAT APPLY TO THE SDK. THESE LAWS INCLUDE RESTRICTIONS ON
+DESTINATIONS, END USERS AND END USE.
+
+14.6 The rights granted in this License Agreement may not be assigned or transferred by either you or Google without the
+prior written approval of the other party. Neither you nor Google shall be permitted to delegate their responsibilities
+or obligations under this License Agreement without the prior written approval of the other party.
+
+14.7 This License Agreement, and your relationship with Google under this License Agreement, shall be governed by the
+laws of the State of California without regard to its conflict of laws provisions. You and Google agree to submit to the
+exclusive jurisdiction of the courts located within the county of Santa Clara, California to resolve any legal matter
+arising from this License Agreement. Notwithstanding this, you agree that Google shall still be allowed to apply for
+injunctive remedies (or an equivalent type of urgent legal relief) in any jurisdiction.
+
+April 10, 2009
+
+
+
+
+Copyright (C) 2016 The Android Open Source Project
+Copyright (c) 2008 Travis Geiselbrecht
+Copyright (c) 2007, Google Inc.
+Copyright (c) 2009-2011, Code Aurora Forum.
+COPYRIGHT (C) 1986 Gary S. Brown.
+Copyright (c) 2009, Google Inc.
+Copyright (C) 2005, 2007 Olivier Gay <olivier.gay@a3.epfl.ch>
+Copyright (c) 2009 Corey Tabaka
+Copyright (c) 2006 Brian Swetland
+Copyright 2001, Manuel J. Petit. All rights reserved.
+Copyright (c) 2008-2010 Travis Geiselbrecht
+Copyright (c) 2008, Google Inc
+Copyright (c) 2009-2011, Code Aurora Forum
+Copyright (c) 2006 Travis Geiselbrecht
+Copyright (C) 2017 The Android Open Source Project
+Copyright (c) 2008, Google Inc.
+Copyright (c) 2010, Code Aurora Forum. All rights reserved.
+Copyright (c) 2009 Travis Geiselbrecht
+Copyright (c) 2008-2009 Travis Geiselbrecht
+Copyright 2001, Travis Geiselbrecht. All rights reserved.
+Copyright (c) 2011, Code Aurora Forum. 
+Copyright (C) 2016 Free Electrons
+Copyright (C) 2016 NextThing Co.
+Copyright (c) 2011, Code Aurora Forum. All rights reserved.
+Copyright (C) 2010 The Android Open Source Project
+Copyright (c) 2008 Brian Swetland
+Copyright (C) 2008 The Android Open Source Project
+Copyright (c) 2012, Code Aurora Forum. All rights reserved.
+Copyright (C) 1995-2005 Mark Adler
+Copyright (c) 2011-2012, Code Aurora Forum. 
+Copyright (c) 2011-2012, Code Aurora Forum. All rights reserved.
+Copyright (c) 2011, Code Aurora Forum
+Copyright (c) 2009, Google Inc.
+ * All rights reserved.
+ *
+ * Copyright (c) 2009-2011, Code Aurora Forum. All rights reserved.
+Copyright (c) 2007 Travis Geiselbrecht
+
+The MIT License
+
+Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated
+documentation files (the "Software"), to deal in the Software without restriction, including without limitation the
+rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit
+persons to whom the Software is furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all copies or substantial portions of the
+Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
+WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
+COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+
+
+
+
+Copyright (C) 1995-2005 Jean-loup Gailly
+Copyright (C) 1995-2004 Jean-loup Gailly
+Copyright (C) 1995-2005 Mark Adler
+Copyright (C) 1995-2004 Mark Adler
+Copyright (C) 1995-2005 Jean-loup Gailly and Mark Adler
+
+The zlib/libpng License
+
+This software is provided 'as-is', without any express or implied warranty. In no event will the authors be held liable
+for any damages arising from the use of this software.
+
+Permission is granted to anyone to use this software for any purpose, including commercial applications, and to alter it
+and redistribute it freely, subject to the following restrictions:
+
+    1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software.
+If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not
+required.
+
+    2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original
+software.
+
+    3. This notice may not be removed or altered from any source distribution.
+
+
+

+ 1442 - 0
app/aboot/aboot.c

@@ -0,0 +1,1442 @@
+/*
+ * Copyright (c) 2009, Google Inc.
+ * All rights reserved.
+ *
+ * Copyright (c) 2009-2011, Code Aurora Forum. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in the
+ *       documentation and/or other materials provided with the distribution.
+ *     * Neither the name of Code Aurora nor
+ *       the names of its contributors may be used to endorse or promote
+ *       products derived from this software without specific prior written
+ *       permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NON-INFRINGEMENT ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include <app.h>
+#include <debug.h>
+#include <arch/arm.h>
+#include <dev/udc.h>
+#include <string.h>
+#include <kernel/thread.h>
+#include <arch/ops.h>
+
+#include <dev/flash.h>
+#include <lib/ptable.h>
+#include <dev/keys.h>
+#include <dev/fbcon.h>
+#include <baseband.h>
+#include <target.h>
+#include <mmc.h>
+#include <partition_parser.h>
+#include <platform.h>
+#include <crypto_hash.h>
+
+#include "image_verify.h"
+#include "recovery.h"
+#include "bootimg.h"
+#include "fastboot.h"
+#include "sparse_format.h"
+#include "mmc.h"
+#include "devinfo.h"
+
+#include "scm.h"
+
+#define EXPAND(NAME) #NAME
+#define TARGET(NAME) EXPAND(NAME)
+#define DEFAULT_CMDLINE "mem=100M console=null";
+
+#ifdef MEMBASE
+#define EMMC_BOOT_IMG_HEADER_ADDR (0xFF000+(MEMBASE))
+#else
+#define EMMC_BOOT_IMG_HEADER_ADDR 0xFF000
+#endif
+
+#define RECOVERY_MODE   0x77665502
+#define FASTBOOT_MODE   0x77665500
+
+static const char *emmc_cmdline = " androidboot.emmc=true";
+static const char *usb_sn_cmdline = " androidboot.serialno=";
+static const char *battchg_pause = " androidboot.mode=charger";
+static const char *auth_kernel = " androidboot.authorized_kernel=true";
+
+static const char *baseband_apq     = " androidboot.baseband=apq";
+static const char *baseband_msm     = " androidboot.baseband=msm";
+static const char *baseband_csfb    = " androidboot.baseband=csfb";
+static const char *baseband_svlte2a = " androidboot.baseband=svlte2a";
+static const char *baseband_mdm     = " androidboot.baseband=mdm";
+static const char *baseband_sglte   = " androidboot.baseband=sglte";
+
+/* Assuming unauthorized kernel image by default */
+static int auth_kernel_img = 0;
+
+static device_info device = {DEVICE_MAGIC, 0, 0};
+
+static struct udc_device surf_udc_device = {
+	.vendor_id	= 0x18d1,
+	.product_id	= 0xD00D,
+	.version_id	= 0x0100,
+	.manufacturer	= "Google",
+	.product	= "Android",
+};
+
+struct atag_ptbl_entry
+{
+	char name[16];
+	unsigned offset;
+	unsigned size;
+	unsigned flags;
+};
+
+char sn_buf[13];
+
+extern int emmc_recovery_init(void);
+
+#if NO_KEYPAD_DRIVER
+extern int fastboot_trigger(void);
+#endif
+
+/* Koshi, 2012.06.12 { */
+static struct ptable *flash_ptable = NULL;
+
+struct ptable *flash_get_ptable(void)
+{
+	return flash_ptable;
+}
+
+unsigned partition_get_index(const char *name)
+{
+    return 0;
+}
+
+/* Get offset of the partition */
+unsigned long long partition_get_offset(int index)
+{
+    return 0;	
+}
+
+/* Get size of the partition */
+unsigned long long partition_get_size(int index)
+{	
+    return 0;	
+}
+
+/*
+ * MMC write function
+ */
+unsigned int mmc_write(unsigned long long data_addr, unsigned int data_len, unsigned int *in)
+{
+    return 0;
+}
+
+unsigned int write_partition(unsigned size, unsigned char *partition)
+{
+    return 0;
+}
+
+unsigned *target_atag_mem(unsigned *ptr)
+{
+    return 0;
+}
+
+int udc_stop(void)
+{
+    return 0;
+}
+
+unsigned board_machtype(void)
+{
+    return 0;
+}
+
+int udc_init(struct udc_device *dev)
+{
+    return 0;
+}
+
+void partition_dump()
+{
+}
+
+int udc_start(void)
+{
+    return 0;
+}
+
+unsigned flash_page_size(void)
+{
+    return 0;
+}
+
+int udc_request_queue(struct udc_endpoint *ept, struct udc_request *_req)
+{
+    return 0;
+}
+
+struct udc_endpoint *udc_endpoint_alloc(unsigned type, unsigned maxpkt)
+{
+    return 0;
+}
+
+struct udc_request *udc_request_alloc(void)
+{
+    return 0;
+}
+
+void udc_request_free(struct udc_request *req)
+{
+}
+
+int udc_register_gadget(struct udc_gadget *gadget)
+{
+	return 0;
+}
+
+void udc_endpoint_free(struct udc_endpoint *ept)
+{
+	/* todo */
+}
+
+int flash_read_ext(struct ptentry *ptn, unsigned extra_per_page, unsigned offset, void *data, unsigned bytes)
+{
+    return 0;
+}
+
+int flash_write(struct ptentry *ptn, unsigned extra_per_page, const void *data, unsigned bytes)
+{
+    return 0;
+}
+
+/* Koshi, 2012.06.12 } */
+
+static void ptentry_to_tag(unsigned **ptr, struct ptentry *ptn)
+{
+	struct atag_ptbl_entry atag_ptn;
+
+	memcpy(atag_ptn.name, ptn->name, 16);
+	atag_ptn.name[15] = '\0';
+	atag_ptn.offset = ptn->start;
+	atag_ptn.size = ptn->length;
+	atag_ptn.flags = ptn->flags;
+	memcpy(*ptr, &atag_ptn, sizeof(struct atag_ptbl_entry));
+	*ptr += sizeof(struct atag_ptbl_entry) / sizeof(unsigned);
+}
+
+void boot_linux(void *kernel, unsigned *tags,
+		const char *cmdline, unsigned machtype,
+		void *ramdisk, unsigned ramdisk_size)
+{
+	unsigned *ptr = tags;
+	unsigned pcount = 0;
+	void (*entry)(unsigned,unsigned,unsigned*) = kernel;
+	struct ptable *ptable;
+	int cmdline_len = 0;
+	int have_cmdline = 0;
+	int pause_at_bootup = 0;
+	unsigned char *cmdline_final = NULL;
+
+	/* CORE */
+	*ptr++ = 2;
+	*ptr++ = 0x54410001;
+
+	if (ramdisk_size) {
+		*ptr++ = 4;
+		*ptr++ = 0x54420005;
+		*ptr++ = (unsigned)ramdisk;
+		*ptr++ = ramdisk_size;
+	}
+
+	ptr = target_atag_mem(ptr);
+
+	if (!target_is_emmc_boot()) {
+		/* Skip NAND partition ATAGS for eMMC boot */
+		if ((ptable = flash_get_ptable()) && (ptable->count != 0)) {
+			int i;
+			*ptr++ = 2 + (ptable->count * (sizeof(struct atag_ptbl_entry) /
+						       sizeof(unsigned)));
+			*ptr++ = 0x4d534d70;
+			for (i = 0; i < ptable->count; ++i)
+				ptentry_to_tag(&ptr, ptable_get(ptable, i));
+		}
+	}
+
+	if (cmdline && cmdline[0]) {
+		cmdline_len = strlen(cmdline);
+		have_cmdline = 1;
+	}
+	if (target_is_emmc_boot()) {
+		cmdline_len += strlen(emmc_cmdline);
+	}
+
+	cmdline_len += strlen(usb_sn_cmdline);
+	cmdline_len += strlen(sn_buf);
+
+	if (target_pause_for_battery_charge()) {
+		pause_at_bootup = 1;
+		cmdline_len += strlen(battchg_pause);
+	}
+
+	if(target_use_signed_kernel() && auth_kernel_img) {
+		cmdline_len += strlen(auth_kernel);
+	}
+
+	/* Determine correct androidboot.baseband to use */
+	switch(target_baseband())
+	{
+		case BASEBAND_APQ:
+			cmdline_len += strlen(baseband_apq);
+			break;
+
+		case BASEBAND_MSM:
+			cmdline_len += strlen(baseband_msm);
+			break;
+
+		case BASEBAND_CSFB:
+			cmdline_len += strlen(baseband_csfb);
+			break;
+
+		case BASEBAND_SVLTE2A:
+			cmdline_len += strlen(baseband_svlte2a);
+			break;
+
+		case BASEBAND_MDM:
+			cmdline_len += strlen(baseband_mdm);
+			break;
+
+		case BASEBAND_SGLTE:
+			cmdline_len += strlen(baseband_sglte);
+			break;
+	}
+
+	if (cmdline_len > 0) {
+		const char *src;
+		char *dst;
+		unsigned n;
+		/* include terminating 0 and round up to a word multiple */
+		n = (cmdline_len + 4) & (~3);
+		*ptr++ = (n / 4) + 2;
+		*ptr++ = 0x54410009;
+		dst = (char *)ptr;
+		/* Save start ptr for debug print */
+		cmdline_final = (char *)ptr;
+		if (have_cmdline) {
+			src = cmdline;
+			while ((*dst++ = *src++));
+		}
+		if (target_is_emmc_boot()) {
+			src = emmc_cmdline;
+			if (have_cmdline) --dst;
+			have_cmdline = 1;
+			while ((*dst++ = *src++));
+		}
+
+		src = usb_sn_cmdline;
+		if (have_cmdline) --dst;
+		have_cmdline = 1;
+		while ((*dst++ = *src++));
+		src = sn_buf;
+		if (have_cmdline) --dst;
+		have_cmdline = 1;
+		while ((*dst++ = *src++));
+
+		if (pause_at_bootup) {
+			src = battchg_pause;
+			if (have_cmdline) --dst;
+			while ((*dst++ = *src++));
+		}
+
+		if(target_use_signed_kernel() && auth_kernel_img) {
+			src = auth_kernel;
+			if (have_cmdline) --dst;
+			while ((*dst++ = *src++));
+		}
+
+		switch(target_baseband())
+		{
+			case BASEBAND_APQ:
+				src = baseband_apq;
+				if (have_cmdline) --dst;
+				while ((*dst++ = *src++));
+				break;
+
+			case BASEBAND_MSM:
+				src = baseband_msm;
+				if (have_cmdline) --dst;
+				while ((*dst++ = *src++));
+				break;
+
+			case BASEBAND_CSFB:
+				src = baseband_csfb;
+				if (have_cmdline) --dst;
+				while ((*dst++ = *src++));
+				break;
+
+			case BASEBAND_SVLTE2A:
+				src = baseband_svlte2a;
+				if (have_cmdline) --dst;
+				while ((*dst++ = *src++));
+				break;
+
+			case BASEBAND_MDM:
+				src = baseband_mdm;
+				if (have_cmdline) --dst;
+				while ((*dst++ = *src++));
+				break;
+
+			case BASEBAND_SGLTE:
+				src = baseband_sglte;
+				if (have_cmdline) --dst;
+				while ((*dst++ = *src++));
+				break;
+		}
+		ptr += (n / 4);
+	}
+
+	/* END */
+	*ptr++ = 0;
+	*ptr++ = 0;
+
+	dprintf(INFO, "booting linux @ %p, ramdisk @ %p (%d)\n",
+		kernel, ramdisk, ramdisk_size);
+	if (cmdline_final)
+		dprintf(INFO, "cmdline: %s\n", cmdline_final);
+
+	enter_critical_section();
+	/* do any platform specific cleanup before kernel entry */
+	platform_uninit();
+	arch_disable_cache(UCACHE);
+	arch_disable_mmu();
+	entry(0, machtype, tags);
+}
+
+unsigned page_size = 0;
+unsigned page_mask = 0;
+
+#define ROUND_TO_PAGE(x,y) (((x) + (y)) & (~(y)))
+
+static unsigned char buf[4096]; //Equal to max-supported pagesize
+
+int boot_linux_from_mmc(void)
+{
+	struct boot_img_hdr *hdr = (void*) buf;
+	struct boot_img_hdr *uhdr;
+	unsigned offset = 0;
+	unsigned long long ptn = 0;
+	unsigned n = 0;
+	const char *cmdline;
+	int index = INVALID_PTN;
+
+	unsigned char *image_addr = 0;
+	unsigned kernel_actual;
+	unsigned ramdisk_actual;
+	unsigned imagesize_actual;
+
+	uhdr = (struct boot_img_hdr *)EMMC_BOOT_IMG_HEADER_ADDR;
+	if (!memcmp(uhdr->magic, BOOT_MAGIC, BOOT_MAGIC_SIZE)) {
+		dprintf(INFO, "Unified boot method!\n");
+		hdr = uhdr;
+		goto unified_boot;
+	}
+	if (!boot_into_recovery) {
+		index = partition_get_index("boot");
+		ptn = partition_get_offset(index);
+		if(ptn == 0) {
+			dprintf(CRITICAL, "ERROR: No boot partition found\n");
+                    return -1;
+		}
+	}
+	else {
+		index = partition_get_index("recovery");
+		ptn = partition_get_offset(index);
+		if(ptn == 0) {
+			dprintf(CRITICAL, "ERROR: No recovery partition found\n");
+                    return -1;
+		}
+	}
+
+	if (mmc_read(ptn + offset, (unsigned int *) buf, page_size)) {
+		dprintf(CRITICAL, "ERROR: Cannot read boot image header\n");
+                return -1;
+	}
+
+	if (memcmp(hdr->magic, BOOT_MAGIC, BOOT_MAGIC_SIZE)) {
+		dprintf(CRITICAL, "ERROR: Invalid boot image header\n");
+                return -1;
+	}
+
+	if (hdr->page_size && (hdr->page_size != page_size)) {
+		page_size = hdr->page_size;
+		page_mask = page_size - 1;
+	}
+
+	/* Authenticate Kernel */
+	if(target_use_signed_kernel() && (!device.is_unlocked) && (!device.is_tampered))
+	{
+		image_addr = (unsigned char *)target_get_scratch_address();
+		kernel_actual = ROUND_TO_PAGE(hdr->kernel_size, page_mask);
+		ramdisk_actual = ROUND_TO_PAGE(hdr->ramdisk_size, page_mask);
+		imagesize_actual = (page_size + kernel_actual + ramdisk_actual);
+
+		offset = 0;
+
+		/* Assuming device rooted at this time */
+		device.is_tampered = 1;
+
+		/* Read image without signature */
+		if (mmc_read(ptn + offset, (void *)image_addr, imagesize_actual))
+		{
+			dprintf(CRITICAL, "ERROR: Cannot read boot image\n");
+				return -1;
+		}
+
+		offset = imagesize_actual;
+		/* Read signature */
+		if(mmc_read(ptn + offset, (void *)(image_addr + offset), page_size))
+		{
+			dprintf(CRITICAL, "ERROR: Cannot read boot image signature\n");
+		}
+		else
+		{
+			auth_kernel_img = image_verify((unsigned char *)image_addr,
+					(unsigned char *)(image_addr + imagesize_actual),
+					imagesize_actual,
+					CRYPTO_AUTH_ALG_SHA256);
+
+			if(auth_kernel_img)
+			{
+				/* Authorized kernel */
+				device.is_tampered = 0;
+			}
+		}
+
+		/* Move kernel and ramdisk to correct address */
+		memmove((void*) hdr->kernel_addr, (char *)(image_addr + page_size), hdr->kernel_size);
+		memmove((void*) hdr->ramdisk_addr, (char *)(image_addr + page_size + kernel_actual), hdr->ramdisk_size);
+
+		/* Make sure everything from scratch address is read before next step!*/
+		if(device.is_tampered)
+		{
+			write_device_info_mmc(&device);
+		#ifdef TZ_TAMPER_FUSE
+			set_tamper_fuse_cmd();
+		#endif
+		}
+	#if USE_PCOM_SECBOOT
+		set_tamper_flag(device.is_tampered);
+	#endif
+	}
+	else
+	{
+		offset += page_size;
+
+		n = ROUND_TO_PAGE(hdr->kernel_size, page_mask);
+		if (mmc_read(ptn + offset, (void *)hdr->kernel_addr, n)) {
+			dprintf(CRITICAL, "ERROR: Cannot read kernel image\n");
+					return -1;
+		}
+		offset += n;
+
+		n = ROUND_TO_PAGE(hdr->ramdisk_size, page_mask);
+		if(n != 0)
+		{
+			if (mmc_read(ptn + offset, (void *)hdr->ramdisk_addr, n)) {
+				dprintf(CRITICAL, "ERROR: Cannot read ramdisk image\n");
+				return -1;
+			}
+		}
+		offset += n;
+	}
+
+unified_boot:
+	dprintf(INFO, "\nkernel  @ %x (%d bytes)\n", hdr->kernel_addr,
+		hdr->kernel_size);
+	dprintf(INFO, "ramdisk @ %x (%d bytes)\n", hdr->ramdisk_addr,
+		hdr->ramdisk_size);
+
+	if(hdr->cmdline[0]) {
+		cmdline = (char*) hdr->cmdline;
+	} else {
+		cmdline = DEFAULT_CMDLINE;
+	}
+	dprintf(INFO, "cmdline = '%s'\n", cmdline);
+
+	dprintf(INFO, "\nBooting Linux\n");
+	boot_linux((void *)hdr->kernel_addr, (unsigned *) hdr->tags_addr,
+		   (const char *)cmdline, board_machtype(),
+		   (void *)hdr->ramdisk_addr, hdr->ramdisk_size);
+
+	return 0;
+}
+
+int boot_linux_from_flash(void)
+{
+	struct boot_img_hdr *hdr = (void*) buf;
+	unsigned n;
+	struct ptentry *ptn;
+	struct ptable *ptable;
+	unsigned offset = 0;
+	const char *cmdline;
+
+	unsigned char *image_addr = 0;
+	unsigned kernel_actual;
+	unsigned ramdisk_actual;
+	unsigned imagesize_actual;
+
+	if (target_is_emmc_boot()) {
+		hdr = (struct boot_img_hdr *)EMMC_BOOT_IMG_HEADER_ADDR;
+		if (memcmp(hdr->magic, BOOT_MAGIC, BOOT_MAGIC_SIZE)) {
+			dprintf(CRITICAL, "ERROR: Invalid boot image header\n");
+			return -1;
+		}
+		goto continue_boot;
+	}
+
+	ptable = flash_get_ptable();
+	if (ptable == NULL) {
+		dprintf(CRITICAL, "ERROR: Partition table not found\n");
+		return -1;
+	}
+
+	if(!boot_into_recovery)
+	{
+	        ptn = ptable_find(ptable, "boot");
+	        if (ptn == NULL) {
+		        dprintf(CRITICAL, "ERROR: No boot partition found\n");
+		        return -1;
+	        }
+	}
+	else
+	{
+	        ptn = ptable_find(ptable, "recovery");
+	        if (ptn == NULL) {
+		        dprintf(CRITICAL, "ERROR: No recovery partition found\n");
+		        return -1;
+	        }
+	}
+
+	if (flash_read(ptn, offset, buf, page_size)) {
+		dprintf(CRITICAL, "ERROR: Cannot read boot image header\n");
+		return -1;
+	}
+
+	if (memcmp(hdr->magic, BOOT_MAGIC, BOOT_MAGIC_SIZE)) {
+		dprintf(CRITICAL, "ERROR: Invalid boot image header\n");
+		return -1;
+	}
+
+	if (hdr->page_size != page_size) {
+		dprintf(CRITICAL, "ERROR: Invalid boot image pagesize. Device pagesize: %d, Image pagesize: %d\n",page_size,hdr->page_size);
+		return -1;
+	}
+
+	/* Authenticate Kernel */
+	if(target_use_signed_kernel() && (!device.is_unlocked) && (!device.is_tampered))
+	{
+		image_addr = (unsigned char *)target_get_scratch_address();
+		kernel_actual = ROUND_TO_PAGE(hdr->kernel_size, page_mask);
+		ramdisk_actual = ROUND_TO_PAGE(hdr->ramdisk_size, page_mask);
+		imagesize_actual = (page_size + kernel_actual + ramdisk_actual);
+
+		offset = 0;
+
+		/* Assuming device rooted at this time */
+		device.is_tampered = 1;
+
+		/* Read image without signature */
+		if (flash_read(ptn, offset, (void *)image_addr, imagesize_actual))
+		{
+			dprintf(CRITICAL, "ERROR: Cannot read boot image\n");
+				return -1;
+		}
+
+		offset = imagesize_actual;
+		/* Read signature */
+		if (flash_read(ptn, offset, (void *)(image_addr + offset), page_size))
+		{
+			dprintf(CRITICAL, "ERROR: Cannot read boot image signature\n");
+		}
+		else
+		{
+
+			/* Verify signature */
+			auth_kernel_img = image_verify((unsigned char *)image_addr,
+						(unsigned char *)(image_addr + imagesize_actual),
+						imagesize_actual,
+						CRYPTO_AUTH_ALG_SHA256);
+
+			if(auth_kernel_img)
+			{
+				/* Authorized kernel */
+				device.is_tampered = 0;
+			}
+		}
+
+		/* Move kernel and ramdisk to correct address */
+		memmove((void*) hdr->kernel_addr, (char *)(image_addr + page_size), hdr->kernel_size);
+		memmove((void*) hdr->ramdisk_addr, (char *)(image_addr + page_size + kernel_actual), hdr->ramdisk_size);
+
+		/* Make sure everything from scratch address is read before next step!*/
+		if(device.is_tampered)
+		{
+			write_device_info_flash(&device);
+		}
+#if USE_PCOM_SECBOOT
+		set_tamper_flag(device.is_tampered);
+#endif
+	}
+	else
+	{
+		offset = page_size;
+
+		n = ROUND_TO_PAGE(hdr->kernel_size, page_mask);
+		if (flash_read(ptn, offset, (void *)hdr->kernel_addr, n)) {
+			dprintf(CRITICAL, "ERROR: Cannot read kernel image\n");
+			return -1;
+		}
+		offset += n;
+
+		n = ROUND_TO_PAGE(hdr->ramdisk_size, page_mask);
+		if (flash_read(ptn, offset, (void *)hdr->ramdisk_addr, n)) {
+			dprintf(CRITICAL, "ERROR: Cannot read ramdisk image\n");
+			return -1;
+		}
+		offset += n;
+	}
+continue_boot:
+	dprintf(INFO, "\nkernel  @ %x (%d bytes)\n", hdr->kernel_addr,
+		hdr->kernel_size);
+	dprintf(INFO, "ramdisk @ %x (%d bytes)\n", hdr->ramdisk_addr,
+		hdr->ramdisk_size);
+
+	if(hdr->cmdline[0]) {
+		cmdline = (char*) hdr->cmdline;
+	} else {
+		cmdline = DEFAULT_CMDLINE;
+	}
+	dprintf(INFO, "cmdline = '%s'\n", cmdline);
+
+	/* TODO: create/pass atags to kernel */
+
+	dprintf(INFO, "\nBooting Linux\n");
+	boot_linux((void *)hdr->kernel_addr, (void *)hdr->tags_addr,
+		   (const char *)cmdline, board_machtype(),
+		   (void *)hdr->ramdisk_addr, hdr->ramdisk_size);
+
+	return 0;
+}
+
+unsigned char info_buf[4096];
+void write_device_info_mmc(device_info *dev)
+{
+	struct device_info *info = (void*) info_buf;
+	unsigned long long ptn = 0;
+	unsigned long long size;
+	int index = INVALID_PTN;
+
+	index = partition_get_index("aboot");
+	ptn = partition_get_offset(index);
+	if(ptn == 0)
+	{
+		return;
+	}
+
+	size = partition_get_size(index);
+
+	memcpy(info, dev, sizeof(device_info));
+
+	if(mmc_write((ptn + size - 512), 512, (void *)info_buf))
+	{
+		dprintf(CRITICAL, "ERROR: Cannot write device info\n");
+		return;
+	}
+}
+
+void read_device_info_mmc(device_info *dev)
+{
+	struct device_info *info = (void*) info_buf;
+	unsigned long long ptn = 0;
+	unsigned long long size;
+	int index = INVALID_PTN;
+
+	index = partition_get_index("aboot");
+	ptn = partition_get_offset(index);
+	if(ptn == 0)
+	{
+		return;
+	}
+
+	size = partition_get_size(index);
+
+	if(mmc_read((ptn + size - 512), (void *)info_buf, 512))
+	{
+		dprintf(CRITICAL, "ERROR: Cannot read device info\n");
+		return;
+	}
+
+	if (memcmp(info->magic, DEVICE_MAGIC, DEVICE_MAGIC_SIZE))
+	{
+		memcpy(info->magic, DEVICE_MAGIC, DEVICE_MAGIC_SIZE);
+		info->is_unlocked = 0;
+		info->is_tampered = 0;
+
+		write_device_info_mmc(info);
+	}
+	memcpy(dev, info, sizeof(device_info));
+}
+
+void write_device_info_flash(device_info *dev)
+{
+	struct device_info *info = (void *) info_buf;
+	struct ptentry *ptn;
+	struct ptable *ptable;
+
+	ptable = flash_get_ptable();
+	if (ptable == NULL)
+	{
+		dprintf(CRITICAL, "ERROR: Partition table not found\n");
+		return;
+	}
+
+	ptn = ptable_find(ptable, "devinfo");
+	if (ptn == NULL)
+	{
+		dprintf(CRITICAL, "ERROR: No boot partition found\n");
+			return;
+	}
+
+	memcpy(info, dev, sizeof(device_info));
+
+	if (flash_write(ptn, 0, (void *)info_buf, page_size))
+	{
+		dprintf(CRITICAL, "ERROR: Cannot write device info\n");
+			return;
+	}
+}
+
+void read_device_info_flash(device_info *dev)
+{
+	struct device_info *info = (void*) info_buf;
+	struct ptentry *ptn;
+	struct ptable *ptable;
+
+	ptable = flash_get_ptable();
+	if (ptable == NULL)
+	{
+		dprintf(CRITICAL, "ERROR: Partition table not found\n");
+		return;
+	}
+
+	ptn = ptable_find(ptable, "devinfo");
+	if (ptn == NULL)
+	{
+		dprintf(CRITICAL, "ERROR: No boot partition found\n");
+			return;
+	}
+
+	if (flash_read(ptn, 0, (void *)info_buf, page_size))
+	{
+		dprintf(CRITICAL, "ERROR: Cannot write device info\n");
+			return;
+	}
+
+	if (memcmp(info->magic, DEVICE_MAGIC, DEVICE_MAGIC_SIZE))
+	{
+		memcpy(info->magic, DEVICE_MAGIC, DEVICE_MAGIC_SIZE);
+		info->is_unlocked = 0;
+		info->is_tampered = 0;
+		write_device_info_flash(info);
+	}
+	memcpy(dev, info, sizeof(device_info));
+}
+
+void write_device_info(device_info *dev)
+{
+	if(target_is_emmc_boot())
+	{
+		write_device_info_mmc(dev);
+	}
+	else
+	{
+		write_device_info_flash(dev);
+	}
+}
+
+void read_device_info(device_info *dev)
+{
+	if(target_is_emmc_boot())
+	{
+		read_device_info_mmc(dev);
+	}
+	else
+	{
+		read_device_info_flash(dev);
+	}
+}
+
+void reset_device_info()
+{
+	dprintf(ALWAYS, "reset_device_info called.");
+	device.is_tampered = 0;
+	write_device_info(&device);
+}
+
+void set_device_root()
+{
+	dprintf(ALWAYS, "set_device_root called.");
+	device.is_tampered = 1;
+	write_device_info(&device);
+}
+
+void cmd_boot(const char *arg, void *data, unsigned sz)
+{
+	unsigned kernel_actual;
+	unsigned ramdisk_actual;
+	static struct boot_img_hdr hdr;
+	char *ptr = ((char*) data);
+
+	if (sz < sizeof(hdr)) {
+		fastboot_fail("invalid bootimage header");
+		return;
+	}
+
+	memcpy(&hdr, data, sizeof(hdr));
+
+	/* ensure commandline is terminated */
+	hdr.cmdline[BOOT_ARGS_SIZE-1] = 0;
+
+	if(target_is_emmc_boot() && hdr.page_size) {
+		page_size = hdr.page_size;
+		page_mask = page_size - 1;
+	}
+
+	kernel_actual = ROUND_TO_PAGE(hdr.kernel_size, page_mask);
+	ramdisk_actual = ROUND_TO_PAGE(hdr.ramdisk_size, page_mask);
+
+	/* sz should have atleast raw boot image */
+	if (page_size + kernel_actual + ramdisk_actual > sz) {
+		fastboot_fail("incomplete bootimage");
+		return;
+	}
+
+	memmove((void*) hdr.kernel_addr, ptr + page_size, hdr.kernel_size);
+	memmove((void*) hdr.ramdisk_addr, ptr + page_size + kernel_actual, hdr.ramdisk_size);
+
+	fastboot_okay("");
+	udc_stop();
+
+	boot_linux((void*) hdr.kernel_addr, (void*) hdr.tags_addr,
+		   (const char*) hdr.cmdline, board_machtype(),
+		   (void*) hdr.ramdisk_addr, hdr.ramdisk_size);
+}
+
+void cmd_erase(const char *arg, void *data, unsigned sz)
+{
+	struct ptentry *ptn;
+	struct ptable *ptable;
+
+	ptable = flash_get_ptable();
+	if (ptable == NULL) {
+		fastboot_fail("partition table doesn't exist");
+		return;
+	}
+
+	ptn = ptable_find(ptable, arg);
+	if (ptn == NULL) {
+		fastboot_fail("unknown partition name");
+		return;
+	}
+
+	if (flash_erase(ptn)) {
+		fastboot_fail("failed to erase partition");
+		return;
+	}
+	fastboot_okay("");
+}
+
+
+void cmd_erase_mmc(const char *arg, void *data, unsigned sz)
+{
+	unsigned long long ptn = 0;
+	unsigned int out[512] = {0};
+	int index = INVALID_PTN;
+
+	index = partition_get_index(arg);
+	ptn = partition_get_offset(index);
+
+	if(ptn == 0) {
+		fastboot_fail("Partition table doesn't exist\n");
+		return;
+	}
+	/* Simple inefficient version of erase. Just writing
+       0 in first block */
+	if (mmc_write(ptn , 512, (unsigned int *)out)) {
+		fastboot_fail("failed to erase partition");
+		return;
+	}
+	fastboot_okay("");
+}
+
+
+void cmd_flash_mmc_img(const char *arg, void *data, unsigned sz)
+{
+	unsigned long long ptn = 0;
+	unsigned long long size = 0;
+	int index = INVALID_PTN;
+
+	if (!strcmp(arg, "partition"))
+	{
+		dprintf(INFO, "Attempt to write partition image.\n");
+		if (write_partition(sz, (unsigned char *) data)) {
+			fastboot_fail("failed to write partition");
+			return;
+		}
+	}
+	else
+	{
+		index = partition_get_index(arg);
+		ptn = partition_get_offset(index);
+		if(ptn == 0) {
+			fastboot_fail("partition table doesn't exist");
+			return;
+		}
+
+		if (!strcmp(arg, "boot") || !strcmp(arg, "recovery")) {
+			if (memcmp((void *)data, BOOT_MAGIC, BOOT_MAGIC_SIZE)) {
+				fastboot_fail("image is not a boot image");
+				return;
+			}
+		}
+
+		size = partition_get_size(index);
+		if (ROUND_TO_PAGE(sz,511) > size) {
+			fastboot_fail("size too large");
+			return;
+		}
+		else if (mmc_write(ptn , sz, (unsigned int *)data)) {
+			fastboot_fail("flash write failure");
+			return;
+		}
+	}
+	fastboot_okay("");
+	return;
+}
+
+void cmd_flash_mmc_sparse_img(const char *arg, void *data, unsigned sz)
+{
+	unsigned int chunk;
+	unsigned int chunk_data_sz;
+	sparse_header_t *sparse_header;
+	chunk_header_t *chunk_header;
+	uint32_t total_blocks = 0;
+	unsigned long long ptn = 0;
+	unsigned long long size = 0;
+	int index = INVALID_PTN;
+
+	index = partition_get_index(arg);
+	ptn = partition_get_offset(index);
+	if(ptn == 0) {
+		fastboot_fail("partition table doesn't exist");
+		return;
+	}
+
+	size = partition_get_size(index);
+	if (ROUND_TO_PAGE(sz,511) > size) {
+		fastboot_fail("size too large");
+		return;
+	}
+
+	/* Read and skip over sparse image header */
+	sparse_header = (sparse_header_t *) data;
+	data += sparse_header->file_hdr_sz;
+	if(sparse_header->file_hdr_sz > sizeof(sparse_header_t))
+	{
+		/* Skip the remaining bytes in a header that is longer than
+		 * we expected.
+		 */
+		data += (sparse_header->file_hdr_sz - sizeof(sparse_header_t));
+	}
+
+	dprintf (SPEW, "=== Sparse Image Header ===\n");
+	dprintf (SPEW, "magic: 0x%x\n", sparse_header->magic);
+	dprintf (SPEW, "major_version: 0x%x\n", sparse_header->major_version);
+	dprintf (SPEW, "minor_version: 0x%x\n", sparse_header->minor_version);
+	dprintf (SPEW, "file_hdr_sz: %d\n", sparse_header->file_hdr_sz);
+	dprintf (SPEW, "chunk_hdr_sz: %d\n", sparse_header->chunk_hdr_sz);
+	dprintf (SPEW, "blk_sz: %d\n", sparse_header->blk_sz);
+	dprintf (SPEW, "total_blks: %d\n", sparse_header->total_blks);
+	dprintf (SPEW, "total_chunks: %d\n", sparse_header->total_chunks);
+
+	/* Start processing chunks */
+	for (chunk=0; chunk<sparse_header->total_chunks; chunk++)
+	{
+		/* Read and skip over chunk header */
+		chunk_header = (chunk_header_t *) data;
+		data += sizeof(chunk_header_t);
+
+		dprintf (SPEW, "=== Chunk Header ===\n");
+		dprintf (SPEW, "chunk_type: 0x%x\n", chunk_header->chunk_type);
+		dprintf (SPEW, "chunk_data_sz: 0x%x\n", chunk_header->chunk_sz);
+		dprintf (SPEW, "total_size: 0x%x\n", chunk_header->total_sz);
+
+		if(sparse_header->chunk_hdr_sz > sizeof(chunk_header_t))
+		{
+			/* Skip the remaining bytes in a header that is longer than
+			 * we expected.
+			 */
+			data += (sparse_header->chunk_hdr_sz - sizeof(chunk_header_t));
+		}
+
+		chunk_data_sz = sparse_header->blk_sz * chunk_header->chunk_sz;
+		switch (chunk_header->chunk_type)
+		{
+			case CHUNK_TYPE_RAW:
+			if(chunk_header->total_sz != (sparse_header->chunk_hdr_sz +
+											chunk_data_sz))
+			{
+				fastboot_fail("Bogus chunk size for chunk type Raw");
+				return;
+			}
+
+			if(mmc_write(ptn + ((uint64_t)total_blocks*sparse_header->blk_sz),
+						chunk_data_sz,
+						(unsigned int*)data))
+			{
+				fastboot_fail("flash write failure");
+				return;
+			}
+			total_blocks += chunk_header->chunk_sz;
+			data += chunk_data_sz;
+			break;
+
+			case CHUNK_TYPE_DONT_CARE:
+			total_blocks += chunk_header->chunk_sz;
+			break;
+
+			case CHUNK_TYPE_CRC:
+			if(chunk_header->total_sz != sparse_header->chunk_hdr_sz)
+			{
+				fastboot_fail("Bogus chunk size for chunk type Dont Care");
+				return;
+			}
+			total_blocks += chunk_header->chunk_sz;
+			data += chunk_data_sz;
+			break;
+
+			default:
+			fastboot_fail("Unknown chunk type");
+			return;
+		}
+	}
+
+	dprintf(INFO, "Wrote %d blocks, expected to write %d blocks\n",
+					total_blocks, sparse_header->total_blks);
+
+	if(total_blocks != sparse_header->total_blks)
+	{
+		fastboot_fail("sparse image write failure");
+	}
+
+	fastboot_okay("");
+	return;
+}
+
+void cmd_flash_mmc(const char *arg, void *data, unsigned sz)
+{
+	sparse_header_t *sparse_header;
+	/* 8 Byte Magic + 2048 Byte xml + Encrypted Data */
+	unsigned int *magic_number = (unsigned int *) data;
+	int ret=0;
+
+	if (magic_number[0] == DECRYPT_MAGIC_0 &&
+		magic_number[1] == DECRYPT_MAGIC_1)
+	{
+#ifdef SSD_ENABLE
+		ret = decrypt_scm((uint32 **) &data, &sz);
+#endif
+		if (ret != 0) {
+			dprintf(CRITICAL, "ERROR: Invalid secure image\n");
+			return;
+		}
+	}
+	else if (magic_number[0] == ENCRYPT_MAGIC_0 &&
+			 magic_number[1] == ENCRYPT_MAGIC_1)
+	{
+#ifdef SSD_ENABLE
+		ret = encrypt_scm((uint32 **) &data, &sz);
+#endif
+		if (ret != 0) {
+			dprintf(CRITICAL, "ERROR: Encryption Failure\n");
+			return;
+		}
+	}
+
+	sparse_header = (sparse_header_t *) data;
+	if (sparse_header->magic != SPARSE_HEADER_MAGIC)
+		cmd_flash_mmc_img(arg, data, sz);
+	else
+		cmd_flash_mmc_sparse_img(arg, data, sz);
+	return;
+}
+
+void cmd_flash(const char *arg, void *data, unsigned sz)
+{
+	struct ptentry *ptn;
+	struct ptable *ptable;
+	unsigned extra = 0;
+
+	ptable = flash_get_ptable();
+	if (ptable == NULL) {
+		fastboot_fail("partition table doesn't exist");
+		return;
+	}
+
+	ptn = ptable_find(ptable, arg);
+	if (ptn == NULL) {
+		fastboot_fail("unknown partition name");
+		return;
+	}
+
+	if (!strcmp(ptn->name, "boot") || !strcmp(ptn->name, "recovery")) {
+		if (memcmp((void *)data, BOOT_MAGIC, BOOT_MAGIC_SIZE)) {
+			fastboot_fail("image is not a boot image");
+			return;
+		}
+	}
+
+	if (!strcmp(ptn->name, "system")
+		|| !strcmp(ptn->name, "userdata")
+		|| !strcmp(ptn->name, "persist")
+		|| !strcmp(ptn->name, "recoveryfs")) {
+		if (flash_ecc_bch_enabled())
+			/* Spare data bytes for 8 bit ECC increased by 4 */
+			extra = ((page_size >> 9) * 20);
+		else
+			extra = ((page_size >> 9) * 16);
+	} else
+		sz = ROUND_TO_PAGE(sz, page_mask);
+
+	dprintf(INFO, "writing %d bytes to '%s'\n", sz, ptn->name);
+	if (flash_write(ptn, extra, data, sz)) {
+		fastboot_fail("flash write failure");
+		return;
+	}
+	dprintf(INFO, "partition '%s' updated\n", ptn->name);
+	fastboot_okay("");
+}
+
+void cmd_continue(const char *arg, void *data, unsigned sz)
+{
+	fastboot_okay("");
+	udc_stop();
+	if (target_is_emmc_boot())
+	{
+		boot_linux_from_mmc();
+	}
+	else
+	{
+		boot_linux_from_flash();
+	}
+}
+
+void cmd_reboot(const char *arg, void *data, unsigned sz)
+{
+	dprintf(INFO, "rebooting the device\n");
+	fastboot_okay("");
+	reboot_device(0);
+}
+
+void cmd_reboot_bootloader(const char *arg, void *data, unsigned sz)
+{
+	dprintf(INFO, "rebooting the device\n");
+	fastboot_okay("");
+	reboot_device(FASTBOOT_MODE);
+}
+
+void cmd_oem_unlock(const char *arg, void *data, unsigned sz)
+{
+	if(!device.is_unlocked)
+	{
+		device.is_unlocked = 1;
+		write_device_info(&device);
+	}
+	fastboot_okay("");
+}
+
+void cmd_oem_devinfo(const char *arg, void *data, unsigned sz)
+{
+	char response[64];
+	snprintf(response, 64, "\tDevice tampered: %s", (device.is_tampered ? "true" : "false"));
+	fastboot_info(response);
+	snprintf(response, 64, "\tDevice unlocked: %s", (device.is_unlocked ? "true" : "false"));
+	fastboot_info(response);
+	fastboot_okay("");
+}
+
+void splash_screen ()
+{
+	struct ptentry *ptn;
+	struct ptable *ptable;
+	struct fbcon_config *fb_display = NULL;
+
+	if (!target_is_emmc_boot())
+	{
+		ptable = flash_get_ptable();
+		if (ptable == NULL) {
+			dprintf(CRITICAL, "ERROR: Partition table not found\n");
+			return;
+		}
+
+		ptn = ptable_find(ptable, "splash");
+		if (ptn == NULL) {
+			dprintf(CRITICAL, "ERROR: No splash partition found\n");
+		} else {
+			fb_display = fbcon_display();
+			if (fb_display) {
+				if (flash_read(ptn, 0, fb_display->base,
+					(fb_display->width * fb_display->height * fb_display->bpp/8))) {
+					fbcon_clear();
+					dprintf(CRITICAL, "ERROR: Cannot read splash image\n");
+				}
+			}
+		}
+	}
+}
+
+void aboot_init(const struct app_descriptor *app)
+{
+	unsigned reboot_mode = 0;
+	unsigned usb_init = 0;
+	unsigned sz = 0;
+
+	/* Setup page size information for nand/emmc reads */
+	if (target_is_emmc_boot())
+	{
+		page_size = 2048;
+		page_mask = page_size - 1;
+	}
+	else
+	{
+		page_size = flash_page_size();
+		page_mask = page_size - 1;
+	}
+
+	if(target_use_signed_kernel())
+	{
+		read_device_info(&device);
+
+	}
+
+	target_serialno((unsigned char *) sn_buf);
+	dprintf(SPEW,"serial number: %s\n",sn_buf);
+	surf_udc_device.serialno = sn_buf;
+
+	/* Check if we should do something other than booting up */
+	if (keys_get_state(KEY_HOME) != 0)
+		boot_into_recovery = 1;
+	if (keys_get_state(KEY_VOLUMEUP) != 0)
+		boot_into_recovery = 1;
+	if(!boot_into_recovery)
+	{
+		if (keys_get_state(KEY_BACK) != 0)
+			goto fastboot;
+		if (keys_get_state(KEY_VOLUMEDOWN) != 0)
+			goto fastboot;
+	}
+
+	#if NO_KEYPAD_DRIVER
+	if (fastboot_trigger())
+		goto fastboot;
+	#endif
+
+	reboot_mode = check_reboot_mode();
+	if (reboot_mode == RECOVERY_MODE) {
+		boot_into_recovery = 1;
+	} else if(reboot_mode == FASTBOOT_MODE) {
+		goto fastboot;
+	}
+
+	if (target_is_emmc_boot())
+	{
+		if(emmc_recovery_init())
+			dprintf(ALWAYS,"error in emmc_recovery_init\n");
+		if(target_use_signed_kernel())
+		{
+			if((device.is_unlocked) || (device.is_tampered))
+			{
+			#ifdef TZ_TAMPER_FUSE
+				set_tamper_fuse_cmd();
+			#endif
+			#if USE_PCOM_SECBOOT
+				set_tamper_flag(device.is_tampered);
+			#endif
+			}
+		}
+		boot_linux_from_mmc();
+	}
+	else
+	{
+		recovery_init();
+#if USE_PCOM_SECBOOT
+	if((device.is_unlocked) || (device.is_tampered))
+		set_tamper_flag(device.is_tampered);
+#endif
+		boot_linux_from_flash();
+	}
+	dprintf(CRITICAL, "ERROR: Could not do normal boot. Reverting "
+		"to fastboot mode.\n");
+
+fastboot:
+
+	target_fastboot_init();
+
+	if(!usb_init)
+		udc_init(&surf_udc_device);
+
+	fastboot_register("boot", cmd_boot);
+
+	if (target_is_emmc_boot())
+	{
+		fastboot_register("flash:", cmd_flash_mmc);
+		fastboot_register("erase:", cmd_erase_mmc);
+	}
+	else
+	{
+		fastboot_register("flash:", cmd_flash);
+		fastboot_register("erase:", cmd_erase);
+	}
+
+	fastboot_register("continue", cmd_continue);
+	fastboot_register("reboot", cmd_reboot);
+	fastboot_register("reboot-bootloader", cmd_reboot_bootloader);
+	fastboot_register("oem unlock", cmd_oem_unlock);
+	fastboot_register("oem device-info", cmd_oem_devinfo);
+	fastboot_publish("product", TARGET(BOARD));
+	fastboot_publish("kernel", "lk");
+	fastboot_publish("serialno", sn_buf);
+	partition_dump();
+	sz = target_get_max_flash_size();
+	fastboot_init(target_get_scratch_address(), sz);
+	udc_start();
+}
+
+APP_START(aboot)
+	.init = aboot_init,
+APP_END
+

+ 97 - 0
app/aboot/bootimg.h

@@ -0,0 +1,97 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the 
+ *    distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef _BOOT_IMAGE_H_
+#define _BOOT_IMAGE_H_
+
+typedef struct boot_img_hdr boot_img_hdr;
+
+#define BOOT_MAGIC "ANDROID!"
+#define BOOT_MAGIC_SIZE 8
+#define BOOT_NAME_SIZE 16
+#define BOOT_ARGS_SIZE 512
+
+struct boot_img_hdr
+{
+    unsigned char magic[BOOT_MAGIC_SIZE];
+
+    unsigned kernel_size;  /* size in bytes */
+    unsigned kernel_addr;  /* physical load addr */
+
+    unsigned ramdisk_size; /* size in bytes */
+    unsigned ramdisk_addr; /* physical load addr */
+
+    unsigned second_size;  /* size in bytes */
+    unsigned second_addr;  /* physical load addr */
+
+    unsigned tags_addr;    /* physical addr for kernel tags */
+    unsigned page_size;    /* flash page size we assume */
+    unsigned unused[2];    /* future expansion: should be 0 */
+
+    unsigned char name[BOOT_NAME_SIZE]; /* asciiz product name */
+    
+    unsigned char cmdline[BOOT_ARGS_SIZE];
+
+    unsigned id[8]; /* timestamp / checksum / sha1 / etc */
+};
+
+/*
+** +-----------------+ 
+** | boot header     | 1 page
+** +-----------------+
+** | kernel          | n pages  
+** +-----------------+
+** | ramdisk         | m pages  
+** +-----------------+
+** | second stage    | o pages
+** +-----------------+
+**
+** n = (kernel_size + page_size - 1) / page_size
+** m = (ramdisk_size + page_size - 1) / page_size
+** o = (second_size + page_size - 1) / page_size
+**
+** 0. all entities are page_size aligned in flash
+** 1. kernel and ramdisk are required (size != 0)
+** 2. second is optional (second_size == 0 -> no second)
+** 3. load each element (kernel, ramdisk, second) at
+**    the specified physical address (kernel_addr, etc)
+** 4. prepare tags at tag_addr.  kernel_args[] is
+**    appended to the kernel commandline in the tags.
+** 5. r0 = 0, r1 = MACHINE_TYPE, r2 = tags_addr
+** 6. if second_size != 0: jump to second_addr
+**    else: jump to kernel_addr
+*/
+
+boot_img_hdr *mkbootimg(void *kernel, unsigned kernel_size,
+                        void *ramdisk, unsigned ramdisk_size,
+                        void *second, unsigned second_size,
+                        unsigned page_size,
+                        unsigned *bootimg_size);
+
+void bootimg_set_cmdline(boot_img_hdr *hdr, const char *cmdline);                
+#endif

+ 45 - 0
app/aboot/devinfo.h

@@ -0,0 +1,45 @@
+/*
+ * * Copyright (c) 2011, Code Aurora Forum. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above
+ *    copyright notice, this list of conditions and the following
+ *    disclaimer in the documentation and/or other materials provided
+ *    with the distribution.
+ *  * Neither the name of Code Aurora Forum, Inc. nor the names of its
+ *    contributors may be used to endorse or promote products derived
+ *    from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef _DEVINFO_H_
+#define _DEVINFO_H_
+
+typedef struct device_info device_info;
+
+#define DEVICE_MAGIC "ANDROID-BOOT!"
+#define DEVICE_MAGIC_SIZE 13
+
+struct device_info
+{
+	unsigned char magic[DEVICE_MAGIC_SIZE];
+	bool is_unlocked;
+	bool is_tampered;
+};
+
+#endif

+ 398 - 0
app/aboot/fastboot.c

@@ -0,0 +1,398 @@
+/*
+ * Copyright (c) 2009, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the 
+ *    distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <debug.h>
+#include <string.h>
+#include <stdlib.h>
+#include <kernel/thread.h>
+#include <kernel/event.h>
+#include <dev/udc.h>
+
+#define MAX_RSP_SIZE 64
+#define MAX_USBFS_BULK_SIZE (16 * 1024)
+
+void boot_linux(void *bootimg, unsigned sz);
+
+/* todo: give lk strtoul and nuke this */
+static unsigned hex2unsigned(const char *x)
+{
+    unsigned n = 0;
+
+    while(*x) {
+        switch(*x) {
+        case '0': case '1': case '2': case '3': case '4':
+        case '5': case '6': case '7': case '8': case '9':
+            n = (n << 4) | (*x - '0');
+            break;
+        case 'a': case 'b': case 'c':
+        case 'd': case 'e': case 'f':
+            n = (n << 4) | (*x - 'a' + 10);
+            break;
+        case 'A': case 'B': case 'C':
+        case 'D': case 'E': case 'F':
+            n = (n << 4) | (*x - 'A' + 10);
+            break;
+        default:
+            return n;
+        }
+        x++;
+    }
+
+    return n;
+}
+
+struct fastboot_cmd {
+	struct fastboot_cmd *next;
+	const char *prefix;
+	unsigned prefix_len;
+	void (*handle)(const char *arg, void *data, unsigned sz);
+};
+
+struct fastboot_var {
+	struct fastboot_var *next;
+	const char *name;
+	const char *value;
+};
+	
+static struct fastboot_cmd *cmdlist;
+
+void fastboot_register(const char *prefix,
+		       void (*handle)(const char *arg, void *data, unsigned sz))
+{
+	struct fastboot_cmd *cmd;
+	cmd = malloc(sizeof(*cmd));
+	if (cmd) {
+		cmd->prefix = prefix;
+		cmd->prefix_len = strlen(prefix);
+		cmd->handle = handle;
+		cmd->next = cmdlist;
+		cmdlist = cmd;
+	}
+}
+
+static struct fastboot_var *varlist;
+
+void fastboot_publish(const char *name, const char *value)
+{
+	struct fastboot_var *var;
+	var = malloc(sizeof(*var));
+	if (var) {
+		var->name = name;
+		var->value = value;
+		var->next = varlist;
+		varlist = var;
+	}
+}
+
+
+static event_t usb_online;
+static event_t txn_done;
+static unsigned char buffer[4096];
+static struct udc_endpoint *in, *out;
+static struct udc_request *req;
+int txn_status;
+
+static void *download_base;
+static unsigned download_max;
+static unsigned download_size;
+
+#define STATE_OFFLINE	0
+#define STATE_COMMAND	1
+#define STATE_COMPLETE	2
+#define STATE_ERROR	3
+
+static unsigned fastboot_state = STATE_OFFLINE;
+
+static void req_complete(struct udc_request *req, unsigned actual, int status)
+{
+	txn_status = status;
+	req->length = actual;
+	event_signal(&txn_done, 0);
+}
+
+static int usb_read(void *_buf, unsigned len)
+{
+	int r;
+	unsigned xfer;
+	unsigned char *buf = _buf;
+	int count = 0;
+
+	if (fastboot_state == STATE_ERROR)
+		goto oops;
+
+	while (len > 0) {
+		xfer = (len > MAX_USBFS_BULK_SIZE) ? MAX_USBFS_BULK_SIZE : len;
+		req->buf = buf;
+		req->length = xfer;
+		req->complete = req_complete;
+		r = udc_request_queue(out, req);
+		if (r < 0) {
+			dprintf(INFO, "usb_read() queue failed\n");
+			goto oops;
+		}
+		event_wait(&txn_done);
+
+		if (txn_status < 0) {
+			dprintf(INFO, "usb_read() transaction failed\n");
+			goto oops;
+		}
+
+		count += req->length;
+		buf += req->length;
+		len -= req->length;
+
+		/* short transfer? */
+		if (req->length != xfer) break;
+	}
+
+	return count;
+
+oops:
+	fastboot_state = STATE_ERROR;
+	return -1;
+}
+
+static int usb_write(void *buf, unsigned len)
+{
+	int r;
+
+	if (fastboot_state == STATE_ERROR)
+		goto oops;
+
+	req->buf = buf;
+	req->length = len;
+	req->complete = req_complete;
+	r = udc_request_queue(in, req);
+	if (r < 0) {
+		dprintf(INFO, "usb_write() queue failed\n");
+		goto oops;
+	}
+	event_wait(&txn_done);
+	if (txn_status < 0) {
+		dprintf(INFO, "usb_write() transaction failed\n");
+		goto oops;
+	}
+	return req->length;
+
+oops:
+	fastboot_state = STATE_ERROR;
+	return -1;
+}
+
+void fastboot_ack(const char *code, const char *reason)
+{
+	char response[MAX_RSP_SIZE];
+
+	if (fastboot_state != STATE_COMMAND)
+		return;
+
+	if (reason == 0)
+		reason = "";
+
+	snprintf(response, MAX_RSP_SIZE, "%s%s", code, reason);
+	fastboot_state = STATE_COMPLETE;
+
+	usb_write(response, strlen(response));
+
+}
+
+void fastboot_info(const char *reason)
+{
+	char response[MAX_RSP_SIZE];
+
+	if (fastboot_state != STATE_COMMAND)
+		return;
+
+	if (reason == 0)
+		return;
+
+	snprintf(response, MAX_RSP_SIZE, "INFO%s", reason);
+
+	usb_write(response, strlen(response));
+}
+
+void fastboot_fail(const char *reason)
+{
+	fastboot_ack("FAIL", reason);
+}
+
+void fastboot_okay(const char *info)
+{
+	fastboot_ack("OKAY", info);
+}
+
+static void cmd_getvar(const char *arg, void *data, unsigned sz)
+{
+	struct fastboot_var *var;
+
+	for (var = varlist; var; var = var->next) {
+		if (!strcmp(var->name, arg)) {
+			fastboot_okay(var->value);
+			return;
+		}
+	}
+	fastboot_okay("");
+}
+
+static void cmd_download(const char *arg, void *data, unsigned sz)
+{
+	char response[MAX_RSP_SIZE];
+	unsigned len = hex2unsigned(arg);
+	int r;
+
+	download_size = 0;
+	if (len > download_max) {
+		fastboot_fail("data too large");
+		return;
+	}
+
+	snprintf(response, MAX_RSP_SIZE, "DATA%08x", len);
+	if (usb_write(response, strlen(response)) < 0)
+		return;
+
+	r = usb_read(download_base, len);
+	if ((r < 0) || ((unsigned) r != len)) {
+		fastboot_state = STATE_ERROR;
+		return;
+	}
+	download_size = len;
+	fastboot_okay("");
+}
+
+static void fastboot_command_loop(void)
+{
+	struct fastboot_cmd *cmd;
+	int r;
+	dprintf(INFO,"fastboot: processing commands\n");
+
+again:
+	while (fastboot_state != STATE_ERROR) {
+		r = usb_read(buffer, MAX_RSP_SIZE);
+		if (r < 0) break;
+		buffer[r] = 0;
+		dprintf(INFO,"fastboot: %s\n", buffer);
+
+		for (cmd = cmdlist; cmd; cmd = cmd->next) {
+			if (memcmp(buffer, cmd->prefix, cmd->prefix_len))
+				continue;
+			fastboot_state = STATE_COMMAND;
+			cmd->handle((const char*) buffer + cmd->prefix_len,
+				    (void*) download_base, download_size);
+			if (fastboot_state == STATE_COMMAND)
+				fastboot_fail("unknown reason");
+			goto again;
+		}
+
+		fastboot_fail("unknown command");
+			
+	}
+	fastboot_state = STATE_OFFLINE;
+	dprintf(INFO,"fastboot: oops!\n");
+}
+
+static int fastboot_handler(void *arg)
+{
+	for (;;) {
+		event_wait(&usb_online);
+		fastboot_command_loop();
+	}
+	return 0;
+}
+
+static void fastboot_notify(struct udc_gadget *gadget, unsigned event)
+{
+	if (event == UDC_EVENT_ONLINE) {
+		event_signal(&usb_online, 0);
+	}
+}
+
+static struct udc_endpoint *fastboot_endpoints[2];
+
+static struct udc_gadget fastboot_gadget = {
+	.notify		= fastboot_notify,
+	.ifc_class	= 0xff,
+	.ifc_subclass	= 0x42,
+	.ifc_protocol	= 0x03,
+	.ifc_endpoints	= 2,
+	.ifc_string	= "fastboot",
+	.ept		= fastboot_endpoints,
+};
+
+int fastboot_init(void *base, unsigned size)
+{
+	thread_t *thr;
+	dprintf(INFO, "fastboot_init()\n");
+
+	download_base = base;
+	download_max = size;
+
+	event_init(&usb_online, 0, EVENT_FLAG_AUTOUNSIGNAL);
+	event_init(&txn_done, 0, EVENT_FLAG_AUTOUNSIGNAL);
+
+#if 0
+
+	in = udc_endpoint_alloc(UDC_TYPE_BULK_IN, 512);
+	if (!in)
+		goto fail_alloc_in;
+	out = udc_endpoint_alloc(UDC_TYPE_BULK_OUT, 512);
+	if (!out)
+		goto fail_alloc_out;
+
+	fastboot_endpoints[0] = in;
+	fastboot_endpoints[1] = out;
+
+	req = udc_request_alloc();
+	if (!req)
+		goto fail_alloc_req;
+
+	if (udc_register_gadget(&fastboot_gadget))
+		goto fail_udc_register;
+
+#endif    
+
+	fastboot_register("getvar:", cmd_getvar);
+	fastboot_register("download:", cmd_download);
+	fastboot_publish("version", "0.5");
+    
+	thr = thread_create("fastboot", fastboot_handler, 0, DEFAULT_PRIORITY, 4096);
+	if (!thr)
+	{
+		goto fail_alloc_in;
+	}
+	thread_resume(thr);    
+	return 0;
+
+fail_udc_register:
+	udc_request_free(req);
+fail_alloc_req:
+	udc_endpoint_free(out);	
+fail_alloc_out:
+	udc_endpoint_free(in);
+fail_alloc_in:
+	return -1;
+}

+ 51 - 0
app/aboot/fastboot.h

@@ -0,0 +1,51 @@
+/*
+ * Copyright (c) 2009, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the 
+ *    distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef __APP_FASTBOOT_H
+#define __APP_FASTBOOT_H
+
+int fastboot_init(void *xfer_buffer, unsigned max);
+
+/* register a command handler 
+ * - command handlers will be called if their prefix matches
+ * - they are expected to call fastboot_okay() or fastboot_fail()
+ *   to indicate success/failure before returning
+ */
+void fastboot_register(const char *prefix,
+		       void (*handle)(const char *arg, void *data, unsigned size));
+
+/* publish a variable readable by the built-in getvar command */
+void fastboot_publish(const char *name, const char *value);
+
+/* only callable from within a command handler */
+void fastboot_okay(const char *result);
+void fastboot_fail(const char *reason);
+void fastboot_info(const char *reason);
+
+
+#endif

+ 472 - 0
app/aboot/recovery.c

@@ -0,0 +1,472 @@
+/* Copyright (c) 2010-2011, Code Aurora Forum. All rights reserved.
+
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *   * Redistributions of source code must retain the above copyright
+ *     notice, this list of conditions and the following disclaimer.
+ *   * Redistributions in binary form must reproduce the above
+ *     copyright notice, this list of conditions and the following
+ *     disclaimer in the documentation and/or other materials provided
+ *     with the distribution.
+ *   * Neither the name of Code Aurora Forum, Inc. nor the names of its
+ *     contributors may be used to endorse or promote products derived
+ *     from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <debug.h>
+#include <arch/arm.h>
+#include <dev/udc.h>
+#include <string.h>
+#include <kernel/thread.h>
+#include <arch/ops.h>
+
+#include <dev/flash.h>
+#include <lib/ptable.h>
+#include <dev/keys.h>
+#include <platform.h>
+#include <partition_parser.h>
+#include <mmc.h>
+
+#include "recovery.h"
+#include "bootimg.h"
+//#include "smem.h"
+
+#define BOOT_FLAGS	1
+#define UPDATE_STATUS	2
+#define ROUND_TO_PAGE(x,y) (((x) + (y)) & (~(y)))
+
+static const int MISC_PAGES = 3;			// number of pages to save
+static const int MISC_COMMAND_PAGE = 1;		// bootloader command is this page
+static char buf[4096];
+unsigned boot_into_recovery = 0;
+
+extern void reset_device_info();
+extern void set_device_root();
+
+int get_recovery_message(struct recovery_message *out)
+{
+	struct ptentry *ptn;
+	struct ptable *ptable;
+	unsigned offset = 0;
+	unsigned pagesize = flash_page_size();
+
+	ptable = flash_get_ptable();
+
+	if (ptable == NULL) {
+		dprintf(CRITICAL, "ERROR: Partition table not found\n");
+		return -1;
+	}
+	ptn = ptable_find(ptable, "misc");
+
+	if (ptn == NULL) {
+		dprintf(CRITICAL, "ERROR: No misc partition found\n");
+		return -1;
+	}
+
+	offset += (pagesize * MISC_COMMAND_PAGE);
+	if (flash_read(ptn, offset, (void *) buf, pagesize)) {
+		dprintf(CRITICAL, "ERROR: Cannot read recovery_header\n");
+		return -1;
+	}
+	memcpy(out, buf, sizeof(*out));
+	return 0;
+}
+
+int set_recovery_message(const struct recovery_message *in)
+{
+	struct ptentry *ptn;
+	struct ptable *ptable;
+	unsigned offset = 0;
+	unsigned pagesize = flash_page_size();
+	unsigned n = 0;
+
+	ptable = flash_get_ptable();
+
+	if (ptable == NULL) {
+		dprintf(CRITICAL, "ERROR: Partition table not found\n");
+		return -1;
+	}
+	ptn = ptable_find(ptable, "misc");
+
+	if (ptn == NULL) {
+		dprintf(CRITICAL, "ERROR: No misc partition found\n");
+		return -1;
+	}
+
+	n = pagesize * (MISC_COMMAND_PAGE + 1);
+
+	if (flash_read(ptn, offset, (void *) SCRATCH_ADDR, n)) {
+		dprintf(CRITICAL, "ERROR: Cannot read recovery_header\n");
+		return -1;
+	}
+
+	offset += (pagesize * MISC_COMMAND_PAGE);
+	offset += SCRATCH_ADDR;
+	memcpy((void *) offset, in, sizeof(*in));
+	if (flash_write(ptn, 0, (void *)SCRATCH_ADDR, n)) {
+		dprintf(CRITICAL, "ERROR: flash write fail!\n");
+		return -1;
+	}
+	return 0;
+}
+
+int read_update_header_for_bootloader(struct update_header *header)
+{
+	struct ptentry *ptn;
+	struct ptable *ptable;
+	unsigned offset = 0;
+	unsigned pagesize = flash_page_size();
+
+	ptable = flash_get_ptable();
+	if (ptable == NULL) {
+		dprintf(CRITICAL, "ERROR: Partition table not found\n");
+		return -1;
+	}
+	ptn = ptable_find(ptable, "cache");
+
+	if (ptn == NULL) {
+		dprintf(CRITICAL, "ERROR: No cache partition found\n");
+		return -1;
+	}
+	if (flash_read(ptn, offset, buf, pagesize)) {
+		dprintf(CRITICAL, "ERROR: Cannot read recovery_header\n");
+		return -1;
+	}
+	memcpy(header, buf, sizeof(*header));
+
+	if (strncmp((char *) header->MAGIC, UPDATE_MAGIC, UPDATE_MAGIC_SIZE))
+	{
+		return -1;
+	}
+	return 0;
+}
+
+int update_firmware_image (struct update_header *header, char *name)
+{
+	struct ptentry *ptn;
+	struct ptable *ptable;
+	unsigned offset = 0;
+	unsigned pagesize = flash_page_size();
+	unsigned pagemask = pagesize -1;
+	unsigned n = 0;
+
+	ptable = flash_get_ptable();
+	if (ptable == NULL) {
+		dprintf(CRITICAL, "ERROR: Partition table not found\n");
+		return -1;
+	}
+
+	ptn = ptable_find(ptable, "cache");
+	if (ptn == NULL) {
+		dprintf(CRITICAL, "ERROR: No cache partition found\n");
+		return -1;
+	}
+
+	offset += header->image_offset;
+	n = (header->image_length + pagemask) & (~pagemask);
+
+	if (flash_read(ptn, offset, (void *) SCRATCH_ADDR, n)) {
+		dprintf(CRITICAL, "ERROR: Cannot read radio image\n");
+		return -1;
+	}
+
+	ptn = ptable_find(ptable, name);
+	if (ptn == NULL) {
+		dprintf(CRITICAL, "ERROR: No %s partition found\n", name);
+		return -1;
+	}
+
+	if (flash_write(ptn, 0, (void *) SCRATCH_ADDR, n)) {
+		dprintf(CRITICAL, "ERROR: flash write fail!\n");
+		return -1;
+	}
+
+	dprintf(INFO, "Partition writen successfully!");
+	return 0;
+}
+
+static int set_ssd_radio_update (char *name)
+{
+	struct ptentry *ptn;
+	struct ptable *ptable;
+	unsigned int ssd_cookie[2] = {0x53534443, 0x4F4F4B49};
+	unsigned pagesize = flash_page_size();
+	unsigned pagemask = pagesize -1;
+	unsigned n = 0;
+
+	ptable = flash_get_ptable();
+	if (ptable == NULL) {
+		dprintf(CRITICAL, "ERROR: Partition table not found\n");
+		return -1;
+	}
+
+	n = (sizeof(ssd_cookie) + pagemask) & (~pagemask);
+
+	ptn = ptable_find(ptable, name);
+	if (ptn == NULL) {
+		dprintf(CRITICAL, "ERROR: No %s partition found\n", name);
+		return -1;
+	}
+
+	if (flash_write(ptn, 0, ssd_cookie, n)) {
+		dprintf(CRITICAL, "ERROR: flash write fail!\n");
+		return -1;
+	}
+
+	dprintf(INFO, "FOTA partition written successfully!");
+	return 0;
+}
+
+int get_boot_info_apps (char type, unsigned int *status)
+{
+    /* Koshi's Note: Seems dedicated for Q* solutions */
+#if 0
+	boot_info_for_apps apps_boot_info;
+	int ret = 0;
+
+	ret = smem_read_alloc_entry(SMEM_BOOT_INFO_FOR_APPS,
+			&apps_boot_info, sizeof(apps_boot_info));
+	if (ret)
+	{
+		dprintf(CRITICAL, "ERROR: unable to read shared memory for apps boot info %d\n",ret);
+		return ret;
+	}
+
+	dprintf(INFO,"boot flag %x update status %x\n",apps_boot_info.boot_flags,
+			apps_boot_info.status.update_status);
+
+	if(type == BOOT_FLAGS)
+		*status = apps_boot_info.boot_flags;
+	else if(type == UPDATE_STATUS)
+		*status = apps_boot_info.status.update_status;
+		
+	return ret;
+#endif	
+    return 0;
+}
+
+/* Bootloader / Recovery Flow
+ *
+ * On every boot, the bootloader will read the recovery_message
+ * from flash and check the command field.  The bootloader should
+ * deal with the command field not having a 0 terminator correctly
+ * (so as to not crash if the block is invalid or corrupt).
+ *
+ * The bootloader will have to publish the partition that contains
+ * the recovery_message to the linux kernel so it can update it.
+ *
+ * if command == "boot-recovery" -> boot recovery.img
+ * else if command == "update-radio" -> update radio image (below)
+ * else -> boot boot.img (normal boot)
+ *
+ * Radio Update Flow
+ * 1. the bootloader will attempt to load and validate the header
+ * 2. if the header is invalid, status="invalid-update", goto #8
+ * 3. display the busy image on-screen
+ * 4. if the update image is invalid, status="invalid-radio-image", goto #8
+ * 5. attempt to update the firmware (depending on the command)
+ * 6. if successful, status="okay", goto #8
+ * 7. if failed, and the old image can still boot, status="failed-update"
+ * 8. write the recovery_message, leaving the recovery field
+ *    unchanged, updating status, and setting command to
+ *    "boot-recovery"
+ * 9. reboot
+ *
+ * The bootloader will not modify or erase the cache partition.
+ * It is recovery's responsibility to clean up the mess afterwards.
+ */
+
+int recovery_init (void)
+{
+	struct recovery_message msg;
+	char partition_name[32];
+	unsigned valid_command = 0;
+	int update_status = 0;
+
+	// get recovery message
+	if (get_recovery_message(&msg))
+		return -1;
+	if (msg.command[0] != 0 && msg.command[0] != 255) {
+		dprintf(INFO, "Recovery command: %.*s\n", sizeof(msg.command), msg.command);
+	}
+	msg.command[sizeof(msg.command)-1] = '\0'; //Ensure termination
+
+	if (!strcmp("boot-recovery",msg.command))
+	{
+		if(!strcmp("RADIO",msg.status))
+		{
+			/* We're now here due to radio update, so check for update status */
+			int ret = get_boot_info_apps(UPDATE_STATUS, (unsigned int *) &update_status);
+
+			if(!ret && (update_status & 0x01))
+			{
+				dprintf(INFO,"radio update success\n");
+				strlcpy(msg.status, "OKAY", sizeof(msg.status));
+			}
+			else
+			{
+				dprintf(INFO,"radio update failed\n");
+				strlcpy(msg.status, "failed-update", sizeof(msg.status));
+			}
+			strlcpy(msg.command, "", sizeof(msg.command));	// clearing recovery command
+			set_recovery_message(&msg);	// send recovery message
+			boot_into_recovery = 1;		// Boot in recovery mode
+			return 0;
+		}
+
+		valid_command = 1;
+		strlcpy(msg.command, "", sizeof(msg.command));	// to safe against multiple reboot into recovery
+		strlcpy(msg.status, "OKAY", sizeof(msg.status));
+		set_recovery_message(&msg);	// send recovery message
+		boot_into_recovery = 1;		// Boot in recovery mode
+		return 0;
+	}
+
+	if (!strcmp("update-radio",msg.command)) {
+		dprintf(INFO,"start radio update\n");
+		valid_command = 1;
+		strlcpy(partition_name, "FOTA", sizeof(partition_name));
+	}
+
+	//Todo: Add support for bootloader update too.
+
+	if(!valid_command) {
+		//We need not to do anything
+		return 0; // Boot in normal mode
+	}
+
+#ifdef OLD_FOTA_UPGRADE
+	if (read_update_header_for_bootloader(&header)) {
+		strlcpy(msg.status, "invalid-update", sizeof(msg.status));
+		goto SEND_RECOVERY_MSG;
+	}
+
+	if (update_firmware_image (&header, partition_name)) {
+		strlcpy(msg.status, "failed-update", sizeof(msg.status));
+		goto SEND_RECOVERY_MSG;
+	}
+#else
+	if (set_ssd_radio_update(partition_name)) {
+		/* If writing to FOTA partition fails */
+		strlcpy(msg.command, "", sizeof(msg.command));
+		strlcpy(msg.status, "failed-update", sizeof(msg.status));
+		goto SEND_RECOVERY_MSG;
+	}
+	else {
+		/* Setting this to check the radio update status */
+		strlcpy(msg.command, "boot-recovery", sizeof(msg.command));
+		strlcpy(msg.status, "RADIO", sizeof(msg.status));
+		goto SEND_RECOVERY_MSG;
+	}
+#endif
+	strlcpy(msg.status, "OKAY", sizeof(msg.status));
+
+SEND_RECOVERY_MSG:
+	set_recovery_message(&msg);	// send recovery message
+	boot_into_recovery = 1;		// Boot in recovery mode
+	reboot_device(0);
+	return 0;
+}
+
+static int emmc_set_recovery_msg(struct recovery_message *out)
+{
+	char *ptn_name = "misc";
+	unsigned long long ptn = 0;
+	unsigned int size = ROUND_TO_PAGE(sizeof(*out),511);
+	unsigned char data[size];
+	int index = INVALID_PTN;
+
+	index = partition_get_index((unsigned char *) ptn_name);
+	ptn = partition_get_offset(index);
+	if(ptn == 0) {
+		dprintf(CRITICAL,"partition %s doesn't exist\n",ptn_name);
+		return -1;
+	}
+	memcpy(data, out, sizeof(*out));
+	if (mmc_write(ptn , size, (unsigned int*)data)) {
+		dprintf(CRITICAL,"mmc write failure %s %d\n",ptn_name, sizeof(*out));
+		return -1;
+	}
+	return 0;
+}
+
+static int emmc_get_recovery_msg(struct recovery_message *in)
+{
+	char *ptn_name = "misc";
+	unsigned long long ptn = 0;
+	unsigned int size = ROUND_TO_PAGE(sizeof(*in),511);
+	unsigned char data[size];
+	int index = INVALID_PTN;
+
+	index = partition_get_index((unsigned char *) ptn_name);
+	ptn = partition_get_offset(index);
+	if(ptn == 0) {
+		dprintf(CRITICAL,"partition %s doesn't exist\n",ptn_name);
+		return -1;
+	}
+	if (mmc_read(ptn , (unsigned int*)data, size)) {
+		dprintf(CRITICAL,"mmc read failure %s %d\n",ptn_name, size);
+		return -1;
+	}
+	memcpy(in, data, sizeof(*in));
+	return 0;
+}
+
+int _emmc_recovery_init(void)
+{
+	int update_status = 0;
+	struct recovery_message msg;
+
+	// get recovery message
+	if(emmc_get_recovery_msg(&msg))
+		return -1;
+	if (msg.command[0] != 0 && msg.command[0] != 255) {
+		dprintf(INFO,"Recovery command: %d %s\n", sizeof(msg.command), msg.command);
+	}
+	msg.command[sizeof(msg.command)-1] = '\0'; //Ensure termination
+
+	if (!strcmp("update-radio",msg.command))
+	{
+		/* We're now here due to radio update, so check for update status */
+		int ret = get_boot_info_apps(UPDATE_STATUS, (unsigned int *) &update_status);
+
+		if(!ret && (update_status & 0x01))
+		{
+			dprintf(INFO,"radio update success\n");
+			strlcpy(msg.status, "OKAY", sizeof(msg.status));
+		}
+		else
+		{
+			dprintf(INFO,"radio update failed\n");
+			strlcpy(msg.status, "failed-update", sizeof(msg.status));
+		}
+		boot_into_recovery = 1;		// Boot in recovery mode
+	}
+	if (!strcmp("reset-device-info",msg.command))
+	{
+		reset_device_info();
+	}
+	if (!strcmp("root-detect",msg.command))
+	{
+		set_device_root();
+	}
+	else
+		return 0;	// do nothing
+
+	strlcpy(msg.command, "", sizeof(msg.command));	// clearing recovery command
+	emmc_set_recovery_msg(&msg);	// send recovery message
+	return 0;
+}

+ 77 - 0
app/aboot/recovery.h

@@ -0,0 +1,77 @@
+/* Copyright (c) 2010, Code Aurora Forum. All rights reserved.
+
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *   * Redistributions of source code must retain the above copyright
+ *     notice, this list of conditions and the following disclaimer.
+ *   * Redistributions in binary form must reproduce the above
+ *     copyright notice, this list of conditions and the following
+ *     disclaimer in the documentation and/or other materials provided
+ *     with the distribution.
+ *   * Neither the name of Code Aurora Forum, Inc. nor the names of its
+ *     contributors may be used to endorse or promote products derived
+ *     from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef _BOOTLOADER_RECOVERY_H
+#define _BOOTLOADER_RECOVERY_H
+
+#define UPDATE_MAGIC       "MSM-RADIO-UPDATE"
+#define UPDATE_MAGIC_SIZE  16
+#define UPDATE_VERSION     0x00010000
+
+
+/* Recovery Message */
+struct recovery_message {
+	char command[32];
+	char status[32];
+	char recovery[1024];
+};
+
+
+struct update_header {
+	unsigned char MAGIC[UPDATE_MAGIC_SIZE];
+
+	unsigned version;
+	unsigned size;
+
+	unsigned image_offset;
+	unsigned image_length;
+
+	unsigned bitmap_width;
+	unsigned bitmap_height;
+	unsigned bitmap_bpp;
+
+	unsigned busy_bitmap_offset;
+	unsigned busy_bitmap_length;
+
+	unsigned fail_bitmap_offset;
+	unsigned fail_bitmap_length;
+};
+
+
+
+int get_recovery_message(struct recovery_message *out);
+int set_recovery_message(const struct recovery_message *in);
+
+int read_update_header_for_bootloader(struct update_header *header);
+int update_firmware_image (struct update_header *header, char *name);
+
+int recovery_init (void);
+
+extern unsigned boot_into_recovery;
+
+#endif

+ 9 - 0
app/aboot/rules.mk

@@ -0,0 +1,9 @@
+LOCAL_DIR := $(GET_LOCAL_DIR)
+
+INCLUDES += -I$(LK_TOP_DIR)/platform/msm_shared/include
+
+OBJS += \
+	$(LOCAL_DIR)/aboot.o \
+	$(LOCAL_DIR)/fastboot.o \
+	$(LOCAL_DIR)/recovery.o
+

+ 48 - 0
app/aboot/sparse_format.h

@@ -0,0 +1,48 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+typedef struct sparse_header {
+  uint32_t  magic;		/* 0xed26ff3a */
+  uint16_t	major_version;	/* (0x1) - reject images with higher major versions */
+  uint16_t	minor_version;	/* (0x0) - allow images with higer minor versions */
+  uint16_t	file_hdr_sz;	/* 28 bytes for first revision of the file format */
+  uint16_t	chunk_hdr_sz;	/* 12 bytes for first revision of the file format */
+  uint32_t	blk_sz;		/* block size in bytes, must be a multiple of 4 (4096) */
+  uint32_t	total_blks;	/* total blocks in the non-sparse output image */
+  uint32_t	total_chunks;	/* total chunks in the sparse input image */
+  uint32_t	image_checksum; /* CRC32 checksum of the original data, counting "don't care" */
+				/* as 0. Standard 802.3 polynomial, use a Public Domain */
+				/* table implementation */
+} sparse_header_t;
+
+#define SPARSE_HEADER_MAGIC	0xed26ff3a
+
+#define CHUNK_TYPE_RAW		0xCAC1
+#define CHUNK_TYPE_FILL		0xCAC2
+#define CHUNK_TYPE_DONT_CARE	0xCAC3
+#define CHUNK_TYPE_CRC		0xCAC4
+
+typedef struct chunk_header {
+  uint16_t	chunk_type;	/* 0xCAC1 -> raw; 0xCAC2 -> fill; 0xCAC3 -> don't care */
+  uint16_t	reserved1;
+  uint32_t	chunk_sz;	/* in blocks in output image */
+  uint32_t	total_sz;	/* in bytes of chunk input file including chunk header and data */
+} chunk_header_t;
+
+/* Following a Raw or Fill chunk is data.  For a Raw chunk, it's the data in chunk_sz * blk_sz.
+ *  For a Fill chunk, it's 4 bytes of the fill data.
+ */
+

+ 72 - 0
app/app.c

@@ -0,0 +1,72 @@
+/*
+ * Copyright (c) 2009 Travis Geiselbrecht
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files
+ * (the "Software"), to deal in the Software without restriction,
+ * including without limitation the rights to use, copy, modify, merge,
+ * publish, distribute, sublicense, and/or sell copies of the Software,
+ * and to permit persons to whom the Software is furnished to do so,
+ * subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+ * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+#include <debug.h>
+#include <app.h>
+#include <kernel/thread.h>
+
+extern const struct app_descriptor __apps_start[];
+extern const struct app_descriptor __apps_end[];
+
+static void start_app(const struct app_descriptor *app);
+
+/* one time setup */
+void apps_init(void)
+{
+	const struct app_descriptor *app;
+
+	/* call all the init routines */
+	for (app = __apps_start; app != __apps_end; app++) {
+		if (app->init)
+			app->init(app);
+	}
+
+	/* start any that want to start on boot */
+	for (app = __apps_start; app != __apps_end; app++) {
+		if (app->entry && (app->flags & APP_FLAG_DONT_START_ON_BOOT) == 0) {
+			start_app(app);
+		}
+	}
+}
+
+static int app_thread_entry(void *arg)
+{
+	const struct app_descriptor *app = (const struct app_descriptor *)arg;
+
+	app->entry(app, NULL);
+
+	return 0;
+}
+
+static void start_app(const struct app_descriptor *app)
+{
+	thread_t *thr;
+	printf("starting app %s\n", app->name);
+
+	thr = thread_create(app->name, &app_thread_entry, (void *)app, DEFAULT_PRIORITY, DEFAULT_STACK_SIZE);
+	if(!thr)
+	{
+		return;
+	}
+	thread_resume(thr);
+}
+

+ 121 - 0
app/clocktests/clock_tests.c

@@ -0,0 +1,121 @@
+/*
+ * Copyright (c) 2012, Code Aurora Forum. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in the
+ *       documentation and/or other materials provided with the distribution.
+ *     * Neither the name of Code Aurora nor
+ *       the names of its contributors may be used to endorse or promote
+ *       products derived from this software without specific prior written
+ *       permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NON-INFRINGEMENT ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include <debug.h>
+#include <string.h>
+#include <app.h>
+#include <platform.h>
+#include <kernel/thread.h>
+#include <err.h>
+
+#if defined(WITH_LIB_CONSOLE) && defined(DEBUG_CLOCK)
+#include <lib/console.h>
+#include <clock.h>
+
+static void print_clock_list()
+{
+	unsigned i;
+	struct clk_lookup *cl;
+	unsigned num;
+	struct clk_list *clock_list = clk_get_list();
+
+	if(!clock_list)
+		return;
+
+	cl = clock_list->clist;
+	num = clock_list->num;
+
+	if(!cl || !num)
+		return;
+
+	printf("Clock list:\n");
+	for(i=0; i < num; i++, cl++)
+	{
+		printf("%s\n", cl->con_id);
+	}
+}
+
+static int clock_measure(const char *id)
+{
+	int ret = NO_ERROR;
+	struct clk *cp, *mcp;
+	unsigned long rate;
+
+	/* Get clk */
+	cp = clk_get(id);
+	if(!cp)
+	{
+		ret = ERR_NOT_VALID;
+		goto measure_error;
+	}
+
+	/* Get measure clk */
+	mcp = clk_get("measure");
+	if(!mcp)
+	{
+		ret = ERR_NOT_VALID;
+		goto measure_error;
+	}
+
+	/* Set parent clk */
+	clk_set_parent(mcp, cp);
+
+	rate = clk_get_rate(mcp);
+
+	printf("Clock %s is running at: %lu Hz.\n", id, rate);
+
+measure_error:
+	return ret;
+}
+
+static int clock_tests(int argc, cmd_args *argv)
+{
+	if (argc < 2) {
+		printf("not enough arguments:\n");
+		printf("%s  <clock-name>\n", argv[0].str);
+		printf("%s  ?\n", argv[0].str);
+		goto out;
+	}
+	if(argv[1].str[0] == '?')
+		print_clock_list();
+	else
+		clock_measure(argv[1].str);
+out:
+	return 0;
+}
+
+STATIC_COMMAND_START
+{ "test_clock", "Test Clock", &clock_tests },
+STATIC_COMMAND_END(clocktests);
+
+#endif
+
+APP_START(clocktests)
+APP_END
+

+ 6 - 0
app/clocktests/rules.mk

@@ -0,0 +1,6 @@
+LOCAL_DIR := $(GET_LOCAL_DIR)
+
+INCLUDES += -I$(LK_TOP_DIR)/platform/msm_shared/include
+
+OBJS += \
+	$(LOCAL_DIR)/clock_tests.o

+ 1354 - 0
app/mt_boot/aee/KEDump.c

@@ -0,0 +1,1354 @@
+/* Copyright Statement:
+*
+* This software/firmware and related documentation ("MediaTek Software") are
+* protected under relevant copyright laws. The information contained herein
+* is confidential and proprietary to MediaTek Inc. and/or its licensors.
+* Without the prior written permission of MediaTek inc. and/or its licensors,
+* any reproduction, modification, use or disclosure of MediaTek Software,
+* and information contained herein, in whole or in part, shall be strictly prohibited.
+*/
+/* MediaTek Inc. (C) 2016. All rights reserved.
+*
+* BY OPENING THIS FILE, RECEIVER HEREBY UNEQUIVOCALLY ACKNOWLEDGES AND AGREES
+* THAT THE SOFTWARE/FIRMWARE AND ITS DOCUMENTATIONS ("MEDIATEK SOFTWARE")
+* RECEIVED FROM MEDIATEK AND/OR ITS REPRESENTATIVES ARE PROVIDED TO RECEIVER ON
+* AN "AS-IS" BASIS ONLY. MEDIATEK EXPRESSLY DISCLAIMS ANY AND ALL WARRANTIES,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED WARRANTIES OF
+* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE OR NONINFRINGEMENT.
+* NEITHER DOES MEDIATEK PROVIDE ANY WARRANTY WHATSOEVER WITH RESPECT TO THE
+* SOFTWARE OF ANY THIRD PARTY WHICH MAY BE USED BY, INCORPORATED IN, OR
+* SUPPLIED WITH THE MEDIATEK SOFTWARE, AND RECEIVER AGREES TO LOOK ONLY TO SUCH
+* THIRD PARTY FOR ANY WARRANTY CLAIM RELATING THERETO. RECEIVER EXPRESSLY ACKNOWLEDGES
+* THAT IT IS RECEIVER'S SOLE RESPONSIBILITY TO OBTAIN FROM ANY THIRD PARTY ALL PROPER LICENSES
+* CONTAINED IN MEDIATEK SOFTWARE. MEDIATEK SHALL ALSO NOT BE RESPONSIBLE FOR ANY MEDIATEK
+* SOFTWARE RELEASES MADE TO RECEIVER'S SPECIFICATION OR TO CONFORM TO A PARTICULAR
+* STANDARD OR OPEN FORUM. RECEIVER'S SOLE AND EXCLUSIVE REMEDY AND MEDIATEK'S ENTIRE AND
+* CUMULATIVE LIABILITY WITH RESPECT TO THE MEDIATEK SOFTWARE RELEASED HEREUNDER WILL BE,
+* AT MEDIATEK'S OPTION, TO REVISE OR REPLACE THE MEDIATEK SOFTWARE AT ISSUE,
+* OR REFUND ANY SOFTWARE LICENSE FEES OR SERVICE CHARGE PAID BY RECEIVER TO
+* MEDIATEK FOR SUCH MEDIATEK SOFTWARE AT ISSUE.
+*/
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <arch/arm/mmu.h>
+#ifdef MTK_GPT_SCHEME_SUPPORT
+#include <platform/partition.h>
+#else
+#include <mt_partition.h>
+#endif
+#include <platform/boot_mode.h>
+#include <platform/ram_console.h>
+#include <platform/mt_reg_base.h>
+#include <platform/mt_rtc.h>
+#include <dev/aee_platform_debug.h>
+#include "mrdump_elf.h"
+#include "KEHeader.h"
+#include <lib/zlib.h>
+#ifdef MTK_3LEVEL_PAGETABLE
+#include <err.h>
+#include <target.h>
+#endif
+#include <platform/mtk_mrdump.h>
+#include <platform/mtk_wdt.h>
+#include <part_interface.h>
+#include "mrdump_private.h"
+#include <log_store_lk.h>
+#include <boot_info.h>
+#include <load_vfy_boot.h>
+
+enum {
+	AEE_LKDUMP_CLEAR = 0,
+	AEE_LKDUMP_RAMCONSOLE_RAW,
+	AEE_LKDUMP_PSTORE_RAW,
+	AEE_LKDUMP_KEDUMP_CRC,
+	AEE_LKDUMP_MINI_RDUMP,
+	AEE_LKDUMP_PROC_CUR_TSK,	//5
+	AEE_LKDUMP_KERNEL_LOG_RAW,
+	AEE_LKDUMP_DISP_DEBUG_RAW,
+	AEE_LKDUMP_DFD20,
+	AEE_LKDUMP_LAST_DRAM,
+	AEE_LKDUMP_LAST_CPU_BUS,	//10
+	AEE_LKDUMP_LAST_SPM_DATA,
+	AEE_LKDUMP_LAST_SPM_SRAM_DATA,
+	AEE_LKDUMP_ATF_LAST,
+	AEE_LKDUMP_ATF_CRASH,
+	AEE_LKDUMP_ATF_RAW,
+	AEE_LKDUMP_ATF_RDUMP,	//16
+	AEE_LKDUMP_CPU_HVFS_RAW,
+	AEE_LKDUMP_SSPM_COREDUMP,
+	AEE_LKDUMP_SSPM_DATA,
+	AEE_LKDUMP_SSPM_XFILE,
+	AEE_LKDUMP_SSPM_LAST_LOG,	//21
+	AEE_LKDUMP_PLLK_LAST_LOG,
+	AEE_LKDUMP_MCDI_DATA,
+	AEE_LKDUMP_SCP_COREDUMP,
+	AEE_LKDUMP_LAST_INFRA_CG,
+	AEE_LKDUMP_ADSP_COREDUMP,
+	AEE_LKDUMP_MCUPM_COREDUMP,
+	AEE_LKDUMP_MCUPM_DATA,
+	AEE_LKDUMP_MCUPM_XFILE,
+	AEE_LKDUMP_MCUPM_LAST_LOG,
+	AEE_LKDUMP_ATF_FOOTPRINT,
+#ifdef MTK_DPM_SUPPORT
+	AEE_LKDUMP_DPM_DATA,
+#endif
+#ifdef MTK_GPU_DFD_SUPPORT
+	AEE_LKDUMP_GPU_DFD,
+#endif
+	//new added before this line please
+	AEE_LKDUMP_ZAEE_LOG,
+	AEE_LKDUMP_HEADER,
+#ifdef MTK_PICACHU_SUPPORT
+	AEE_LKDUMP_PICACHU_LOG,
+#endif
+#ifdef MICROTRUST_TEE_DUMP_SUPPORT
+	AEE_LKDUMP_TEEI_LOG,
+#endif
+	AEE_LKDUMP_UNKNOWN
+};
+
+static struct aee_db_file_info adfi[AEE_PLAT_DEBUG_NUM] = {
+	[AEE_PLAT_DFD20] = { "DFD20.dfd", 0x40000, AEE_LKDUMP_DFD20},         /* 256 KB */
+	[AEE_PLAT_DRAM] = { "SYS_LAST_DRAM", 0x2400, AEE_LKDUMP_LAST_DRAM},       /*   9 KB */
+	[AEE_PLAT_CPU_BUS] = { "SYS_LAST_CPU_BUS", 0x10000, AEE_LKDUMP_LAST_CPU_BUS}, /*  64 KB */
+	[AEE_PLAT_SPM_DATA] = { "SYS_LAST_SPM_DATA", 0x1000, AEE_LKDUMP_LAST_SPM_DATA}, /*  4 KB */
+        [AEE_PLAT_SPM_SRAM_DATA] = { "SYS_LAST_SPM_SRAM_DATA", 0x1000, AEE_LKDUMP_LAST_SPM_SRAM_DATA}, /*  4 KB */
+	[AEE_PLAT_ATF_LAST_LOG] = { "SYS_ATF_LAST", 0x20000, AEE_LKDUMP_ATF_LAST}, /* 128KB */
+	[AEE_PLAT_ATF_CRASH_REPORT] = { "SYS_ATF_CRASH", 0x30000, AEE_LKDUMP_ATF_CRASH}, /* 64KB+128KB */
+	[AEE_PLAT_ATF_RAW_LOG] = { "SYS_ATF_RAW_LOG", 0x60000, AEE_LKDUMP_ATF_RAW}, /* 384 KB */
+	[AEE_PLAT_ATF_RDUMP_LOG] = { "SYS_ATF_RDUMP", 0x80000, AEE_LKDUMP_ATF_RDUMP}, /* 512KB */
+	[AEE_PLAT_HVFS] = { "SYS_CPUHVFS_RAW", 0x3000, AEE_LKDUMP_CPU_HVFS_RAW}, /* 12 KB */
+#ifdef MTK_TINYSYS_SSPM_SUPPORT
+	[AEE_PLAT_SSPM_COREDUMP] = { "SYS_SSPM_COREDUMP", 0x40080, AEE_LKDUMP_SSPM_COREDUMP}, /* 256KB + 128Byte */
+	[AEE_PLAT_SSPM_DATA] = { "SYS_SSPM_DATA", 0x400, AEE_LKDUMP_SSPM_DATA}, /* 1KB */
+	[AEE_PLAT_SSPM_XFILE] = { "SYS_SSPM_XFILE", 0xA0000, AEE_LKDUMP_SSPM_XFILE}, /* 640KB */
+	[AEE_PLAT_SSPM_LAST_LOG] = { "SYS_SSPM_LAST_LOG", 0x400, AEE_LKDUMP_SSPM_LAST_LOG}, /* 1KB */
+#endif
+	[AEE_PLAT_PLLK_LAST_LOG] = { "SYS_PLLK_LAST_LOG", 0x40000, AEE_LKDUMP_PLLK_LAST_LOG}, /* 256KB */
+	[AEE_PLAT_LOG_DUR_LKDUMP] = { "SYS_LOG_DUR_LKDUMP", 0x40000, AEE_PLAT_LOG_DUR_LKDUMP}, /* 256KB */
+	[AEE_PLAT_MCDI_DATA] = { "SYS_MCDI_DATA", 0x800, AEE_LKDUMP_MCDI_DATA}, /* 2KB, size will modified by plat. */
+#ifdef MTK_TINYSYS_SCP_SUPPORT
+	[AEE_PLAT_SCP_COREDUMP] = { "SYS_SCP_DUMP.gz", 0xA0000, AEE_LKDUMP_SCP_COREDUMP}, /* 640KB */
+#endif
+	[AEE_PLAT_INFRA_CG] = { "SYS_LAST_INFRA_CG", 0x1000, AEE_LKDUMP_LAST_INFRA_CG}, /*  4 KB */
+#ifdef MTK_AUDIODSP_SUPPORT
+	[AEE_PLAT_ADSP_COREDUMP] = { "SYS_ADSP_COREDUMP", 0x11000, AEE_LKDUMP_ADSP_COREDUMP}, /* 68KB */
+#endif
+#ifdef MTK_TINYSYS_MCUPM_SUPPORT
+	[AEE_PLAT_MCUPM_COREDUMP] = { "SYS_MCUPM_COREDUMP", 0x40080, AEE_LKDUMP_MCUPM_COREDUMP}, /* 256KB + 128Byte */
+	[AEE_PLAT_MCUPM_DATA] = { "SYS_MCUPM_DATA", 0x400, AEE_LKDUMP_MCUPM_DATA}, /* 1KB */
+	[AEE_PLAT_MCUPM_XFILE] = { "SYS_MCUPM_XFILE", 0xA0000, AEE_LKDUMP_MCUPM_XFILE}, /* 640KB */
+	[AEE_PLAT_MCUPM_LAST_LOG] = { "SYS_MCUPM_LAST_LOG", 0x400, AEE_LKDUMP_MCUPM_LAST_LOG}, /* 1KB */
+#endif
+#ifdef MTK_PICACHU_SUPPORT
+#ifdef MTK_PICACHU_SUPPORT_DUMP_SYS_PI
+        [AEE_PLAT_PICACHU_LOG] = { "SYS_PICACHU_LOG", 0x17F000, AEE_LKDUMP_PICACHU_LOG}, /*  1020KB + 512 KB */
+#else
+	[AEE_PLAT_PICACHU_LOG] = { "SYS_PICACHU_LOG", 0x80000, AEE_LKDUMP_PICACHU_LOG}, /*  512 KB */
+#endif
+#endif
+#ifdef MICROTRUST_TEE_DUMP_SUPPORT
+	[AEE_PLAT_TEEI_LOG] = { "SYS_TEEI_LOG", 0x20000, AEE_LKDUMP_TEEI_LOG}, /* 128 KB */
+#endif
+	[AEE_PLAT_ATF_FOOTPRINT_LOG] = { "SYS_ATF_FOOTPRINT", 0x800, AEE_LKDUMP_ATF_FOOTPRINT}, /* 2KB */
+#ifdef MTK_DPM_SUPPORT
+	[AEE_PLAT_DPM_DATA] = { "SYS_DPM_DATA", 0x10400, AEE_LKDUMP_DPM_DATA}, /* 65KB */
+#endif
+#ifdef MTK_GPU_DFD_SUPPORT
+	[AEE_PLAT_GPU_DFD] = { "GPU.dfd", 0x100000, AEE_LKDUMP_GPU_DFD}, /* 1024KB */
+#endif
+};
+
+struct aee_db_file_info* get_file_info(void)
+{
+	return adfi;
+}
+
+/**************************/
+/* ----------------   */
+/* RAM_CONSOLE_DRAM_ADDR  */
+/* (1M align)         */
+/* +RAM_CONSOLE_DRAM_SIZE */
+/*            */
+/* ----------------   */
+/* +0xe0000       */
+/*            */
+/* ----------------   */
+/* KE_RESERVED_MEM_ADDR   */
+/*            */
+/* ----------------   */
+/* RAMDISK_LOAD_ADDR      */
+/**************************/
+static unsigned int ke_reserved_mem_addr_atag(void)
+{
+	unsigned int addr;
+	unsigned int size;
+
+	mrdump_mini_header_addr_size(&addr, &size);
+
+	return addr;
+}
+#define KE_RESERVED_MEM_ADDR ke_reserved_mem_addr_atag()
+#define EXPDB_RESERVED_OTHER    (3 * 1024 * 1024) //reserved expdb for control block and pl/lk log
+#if defined(MTK_MLC_NAND_SUPPORT) || defined(MTK_TLC_NAND_SUPPORT)
+#define MEM_EXPDB_SIZE 0x300000
+static char *mem_expdb;
+#endif
+struct ke_dev {
+	part_dev_t *dev;
+	uint  part_id;
+	u64 ptn;
+	u64 part_size;
+};
+
+static struct ke_dev dev;
+
+struct elfhdr {
+	void *start;
+	unsigned int e_machine;
+	unsigned int e_phoff;
+	unsigned int e_phnum;
+};
+
+struct kedump_crc {
+	unsigned int ram_console_crc;
+	unsigned int pstore_crc;
+};
+
+static struct kedump_crc kc;
+
+extern BOOT_ARGUMENT *g_boot_arg;
+#define SZLOG 20480
+static char logbuf[SZLOG];
+
+extern bool ram_console_should_restore(unsigned char *tmp_ram_console);
+#ifdef MTK_PMIC_FULL_RESET
+extern bool ram_console_reboot_by_cold_reset(void);
+#endif
+
+static unsigned int last_dump_step;
+
+int sLOG(char *fmt, ...)
+{
+	va_list args;
+	static int pos = 0;
+	va_start(args, fmt);
+	if (pos < SZLOG - 1) /* vsnprintf bug */
+		pos += vsnprintf(logbuf + pos, SZLOG - pos - 1, fmt, args);
+	va_end(args);
+	return 0;
+}
+
+#define LOG(fmt, ...)           \
+    do {    \
+        sLOG(fmt, ##__VA_ARGS__);       \
+        printf(fmt, ##__VA_ARGS__); \
+    } while (0)
+
+#define LOGD(fmt, ...)              \
+    sLOG(fmt, ##__VA_ARGS__)
+
+#define elf_note    elf32_note
+#define PHDR_PTR(ehdr, phdr, mem)       \
+    (ehdr->e_machine == EM_ARM ? ((struct elf32_phdr*)phdr)->mem : ((struct elf64_phdr*)phdr)->mem)
+
+#define PHDR_TYPE(ehdr, phdr) PHDR_PTR(ehdr, phdr, p_type)
+#define PHDR_VADDR(ehdr, phdr) PHDR_PTR(ehdr, phdr, p_vaddr)
+#define PHDR_ADDR(ehdr, phdr) PHDR_PTR(ehdr, phdr, p_paddr)
+#define PHDR_SIZE(ehdr, phdr) PHDR_PTR(ehdr, phdr, p_filesz)
+#define PHDR_MEMSZ(ehdr, phdr) PHDR_PTR(ehdr, phdr, p_memsz)
+#define PHDR_FLAGS(ehdr, phdr) PHDR_PTR(ehdr, phdr, p_flags)
+#define PHDR_ALIGN(ehdr, phdr) PHDR_PTR(ehdr, phdr, p_align)
+#define PHDR_OFF(ehdr, phdr) PHDR_PTR(ehdr, phdr, p_offset)
+#define PHDR_INDEX(ehdr, i)         \
+    (ehdr->e_machine == EM_ARM ? ehdr->start + ehdr->e_phoff + sizeof(struct elf32_phdr) * i : ehdr->start + ehdr->e_phoff + sizeof(struct elf64_phdr) *i)
+
+#ifndef ALIGN
+#define ALIGN(x, a) (((x) + ((a) -1)) & ~((a) -1))
+#endif
+
+extern uint64_t v2p_64(uint64_t vptr);
+extern uint64_t v2p_32(uint64_t vptr);
+static struct mrdump_control_block g_mcb;
+
+static uint64_t _get_mpt(struct mrdump_control_block *mcb)
+{
+	if (mcb == NULL) {
+		LOG("%s: mrdump_cb is NULL\n", __func__);
+		return 0;
+	}
+
+	if (memcmp(mcb->sig, MRDUMP_GO_DUMP, 8) == 0) {
+		struct mrdump_machdesc *mmp = &mcb->machdesc;
+		return mmp->master_page_table;
+	} else {
+		LOG("mrdump_cb: unexpected sig error:0x%llx in %s\n", *(uint64_t *)mcb, __func__);
+		return 0;
+	}
+}
+
+uint64_t get_mpt(void)
+{
+	return _get_mpt(&g_mcb);
+}
+
+static void get_vmalloc_range(struct mrdump_control_block *mcb, uint64_t *vmalloc_start, uint64_t *vmalloc_end)
+{
+	if (mcb == NULL || vmalloc_start == NULL || vmalloc_end == NULL)
+		return;
+
+	if (memcmp(mcb->sig, MRDUMP_GO_DUMP, 8) == 0) {
+		struct mrdump_machdesc *mmp = &mcb->machdesc;
+		*vmalloc_start = mmp->vmalloc_start;
+		*vmalloc_end = mmp->vmalloc_end;
+	} else {
+		*vmalloc_start = 0;
+		*vmalloc_end = 0;
+	}
+}
+
+static bool is_dram_address(uint64_t addr, struct mrdump_control_block *mcb)
+{
+	if (mcb == NULL)
+		return false;
+
+	if (memcmp(mcb->sig, MRDUMP_GO_DUMP, 8) == 0) {
+		struct mrdump_machdesc *mmp = &mcb->machdesc;
+		return (addr >= mmp->dram_start && addr < mmp->dram_end);
+	} else {
+		return false;
+	}
+}
+
+static int is_arm_32bit(struct mrdump_control_block *mcb, uint64_t vaddr)
+{
+	bool isret = (vaddr <= 0xffffffffUL) ? true : false;
+	if (mcb == NULL)
+		return isret;
+
+	if (memcmp(mcb->sig, MRDUMP_GO_DUMP, 8) == 0) {
+		struct mrdump_machdesc *mmp = &mcb->machdesc;
+		return (mmp->page_offset > 0 && mmp->page_offset <= 0xffffffffUL);
+	} else {
+		return isret;
+	}
+}
+
+static unsigned int calculate_crc32(void *data, unsigned int len)
+{
+	unsigned int mycrc;
+	unsigned int ret;
+
+	mycrc = crc32(0L, Z_NULL, 0);
+	ret = crc32(mycrc, data, len);
+	LOG("kedump: crc = 0x%x\n", ret);
+	return ret;
+}
+
+static struct elfhdr* kedump_elf_hdr(void)
+{
+	char *ei;
+	static struct elfhdr kehdr;
+	static struct elfhdr *ehdr = (void*)-1;
+	if (ehdr != (void*)-1)
+		return ehdr;
+	ehdr = NULL;
+	kehdr.start = (void*)(KE_RESERVED_MEM_ADDR);
+	LOG("kedump: KEHeader %p\n", kehdr.start);
+	if (kehdr.start) {
+		ei = (char*)kehdr.start; //elf_hdr.e_ident
+		LOG("kedump: read header 0x%p[0x%x%x%x%x]\n", ei, ei[0], ei[1], ei[2], ei[3]);
+		/* valid elf header */
+		if (ei[0] == 0x7f && ei[1] == 'E' && ei[2] == 'L' && ei[3] == 'F') {
+			kehdr.e_machine = ((struct elf32_hdr*)(kehdr.start))->e_machine;
+			if (kehdr.e_machine == EM_ARM) {
+				kehdr.e_phnum = ((struct elf32_hdr*)(kehdr.start))->e_phnum;
+				kehdr.e_phoff = ((struct elf32_hdr*)(kehdr.start))->e_phoff;
+				ehdr = &kehdr;
+			} else if (kehdr.e_machine == EM_AARCH64) {
+				kehdr.e_phnum = ((struct elf64_hdr*)(kehdr.start))->e_phnum;
+				kehdr.e_phoff = ((struct elf64_hdr*)(kehdr.start))->e_phoff;
+				ehdr = &kehdr;
+			}
+		}
+		if (ehdr == NULL)
+			LOG("kedump: invalid header[0x%x%x%x%x]\n", ei[0], ei[1], ei[2], ei[3]);
+	}
+	LOG("kedump: mach[0x%x], phnum[0x%x], phoff[0x%x]\n", kehdr.e_machine, kehdr.e_phnum, kehdr.e_phoff);
+	return ehdr;
+}
+
+static int kedump_dev_open(void)
+{
+	int index;
+	index = partition_get_index(AEE_IPANIC_PLABLE);
+	dev.dev = mt_part_get_device();
+	if (index == -1 || dev.dev == NULL) {
+		LOG("kedump: no %s partition[%d]\n", AEE_IPANIC_PLABLE, index);
+		return -1;
+	}
+#if (defined(MTK_UFS_SUPPORT) || defined(MTK_NEW_COMBO_EMMC_SUPPORT))
+	dev.part_id = partition_get_region(index);
+#endif
+	dev.ptn = partition_get_offset(index);
+	dev.part_size = partition_get_size(index);
+	if (dev.part_size < EXPDB_RESERVED_OTHER) {
+		LOG("kedump: partition size(%llx) is lesser then reserved!(%llx)\n", dev.part_size, (unsigned long long)EXPDB_RESERVED_OTHER);
+		return -1;
+	}
+	dev.part_size -= EXPDB_RESERVED_OTHER; //reserved expdb for others
+	LOG("kedump: partiton %d[%llx - %llx]\n", index, dev.ptn, dev.part_size);
+
+	return 0;
+}
+
+#if defined(MTK_MLC_NAND_SUPPORT) || defined(MTK_TLC_NAND_SUPPORT)
+unsigned long long mem_expdb_write(void *data, unsigned long long offset, unsigned long sz)
+{
+	if ((offset + sz) > MEM_EXPDB_SIZE) {
+		LOG("overflow!\n");
+		return 0;
+	}
+	memcpy((mem_expdb + offset), data, (unsigned long)sz);
+
+	return sz;
+}
+#endif
+
+#define TRUNK 0x8000
+static unsigned long long kedump_dev_write (unsigned long long offset, uint64_t data, unsigned long sz)
+{
+	unsigned long long size_wrote = 0;
+	vaddr_t vaddr = (uint32_t)data;
+	vaddr_t memsrc = vaddr;
+	uint8_t *trunk;
+	unsigned long rest = sz;
+
+	if (!data)
+		return 0;
+
+	trunk = malloc(TRUNK);
+	if (trunk == NULL) {
+		LOG("kedump: malloc failed\n");
+		return 0;
+	}
+
+	LOG("kedump: offset:0x%llx, data:0x%llx, size:0x%lx\n", offset, data, sz);
+#ifdef MTK_3LEVEL_PAGETABLE
+	{
+		/*int ret;*/
+		uint64_t start = ROUNDDOWN((uint64_t)data, (uint64_t)PAGE_SIZE);
+		vaddr = ROUNDUP((vaddr_t)target_get_scratch_address(), PAGE_SIZE);
+		uint32_t secsize = ROUNDUP((uint32_t)(data - start + sz), PAGE_SIZE);
+		if (start >= DRAM_PHY_ADDR) {
+			/* minirdump: minirdump will dump memory in DRAM, we must allocate it first */
+
+			int map_ok = arch_mmu_map((uint64_t) start, vaddr,
+				     MMU_MEMORY_TYPE_NORMAL_WRITE_BACK | MMU_MEMORY_AP_P_RW_U_NA, secsize);
+			if (map_ok != NO_ERROR)
+				LOG("kedump: map error\n");
+			memsrc = vaddr + (uint32_t)(data - start);
+		}
+		/*LOG("kedump: start:0x%llx, vaddr:0x%x, secsize:0x%x, memsrc:0x%x\n", start, vaddr, secsize, memsrc);*/
+	}
+#endif
+	if (offset >= dev.part_size || sz > dev.part_size - offset) {
+		if (trunk != NULL)
+			free(trunk);
+		LOG("kedump: write oversize %lx -> %llx > %llx\n", sz, offset, dev.part_size);
+		return 0;
+	}
+	while (rest > 0) {
+		unsigned long write_sz;
+		memset(trunk, 0x0, TRUNK);
+		if (rest <= TRUNK) {
+			write_sz = rest;
+		} else {
+			write_sz = TRUNK;
+		}
+		memcpy(trunk, (void *)(memsrc + (sz - rest)), write_sz);
+
+#if (defined(MTK_UFS_SUPPORT) || defined(MTK_EMMC_SUPPORT))
+#if (defined(MTK_UFS_SUPPORT) || defined(MTK_NEW_COMBO_EMMC_SUPPORT))
+	size_wrote += dev.dev->write(dev.dev, trunk, dev.ptn + offset, write_sz, dev.part_id);
+#else
+	size_wrote += dev.dev->write(dev.dev, trunk, dev.ptn + offset, write_sz);
+#endif
+#elif defined(MTK_NAND_SUPPORT)
+	size_wrote += dev.dev->write(dev.dev, trunk, (unsigned long)dev.ptn + offset, write_sz);
+#endif
+
+#if defined(MTK_MLC_NAND_SUPPORT) || defined(MTK_TLC_NAND_SUPPORT)
+	size_wrote += mem_expdb_write(trunk, offset, write_sz);
+#endif
+		offset += write_sz;
+		rest -= write_sz;
+	}
+	if ((long long)size_wrote <= 0) {
+		LOG("kedump: write failed(%llx), %lx@%llx -> %llx\n", size_wrote, sz, data, offset);
+		size_wrote = 0;
+	}
+	free(trunk);
+#ifdef MTK_3LEVEL_PAGETABLE
+	{
+		/* restore vaddr */
+		uint64_t start = ROUNDDOWN((uint64_t)data, (uint64_t)PAGE_SIZE);
+		uint32_t secsize = ROUNDUP((uint32_t)(data - start + sz), PAGE_SIZE);
+		if (start >= DRAM_PHY_ADDR) {
+			int map_ok = arch_mmu_map(vaddr, vaddr, MMU_MEMORY_TYPE_NORMAL_WRITE_BACK | MMU_MEMORY_AP_P_RW_U_NA, secsize);
+			if (map_ok != NO_ERROR) {
+				LOG("kedump: arch_mmu_map restore error: map_ok=%d, vaddr=0x%08lx\n",
+					map_ok, (unsigned long)vaddr);
+			}
+		}
+	}
+#endif
+	return size_wrote;
+}
+
+uint64_t kedump_mem_read(uint64_t data, unsigned long sz, void *buf)
+{
+	uint64_t size_read = 0;
+	vaddr_t vaddr = (uint32_t)data;
+	vaddr_t memsrc = vaddr;
+	uint8_t *trunk = NULL;
+	unsigned long rest = sz;
+	unsigned long buf_offset = 0;
+
+	if(!is_dram_address(data, &g_mcb) || !is_dram_address((data + sz - 1), &g_mcb)) {
+		LOG("kedump: illegal address:0x%llx(sz:0x%lx)\n", data, sz);
+		return 0;
+	}
+
+	trunk = malloc(TRUNK);
+	if (trunk == NULL) {
+		LOG("kedump: malloc failed in %s\n", __func__);
+		return 0;
+	}
+	/* LOG("kedump: read data:0x%llx, size:0x%lx\n", data, sz); */
+#ifdef MTK_3LEVEL_PAGETABLE
+	{
+		/*int ret;*/
+		uint64_t start = ROUNDDOWN((uint64_t)data, (uint64_t)PAGE_SIZE);
+		vaddr = ROUNDUP((vaddr_t)target_get_scratch_address(), PAGE_SIZE);
+		uint32_t secsize = ROUNDUP((uint32_t)(data - start + sz), PAGE_SIZE);
+		if (start >= DRAM_PHY_ADDR) {
+			/* minirdump: minirdump will dump memory in DRAM, we must allocate it first */
+
+			int map_ok = arch_mmu_map((uint64_t) start, vaddr,
+				     MMU_MEMORY_TYPE_NORMAL_WRITE_BACK | MMU_MEMORY_AP_P_RW_U_NA, secsize);
+			if (map_ok != NO_ERROR)
+				LOG("kedump: map error in %s\n", __func__);
+			memsrc = vaddr + (uint32_t)(data - start);
+		} else {
+			LOG("kedump: try to map address:0x%llx(sz:0x%lx)\n", data, sz);
+			LOG("kedump: illegal rounddown:0x%llx\n", start);
+			free(trunk);
+			return 0;
+		}
+		/*LOG("kedump: start:0x%llx, vaddr:0x%x, secsize:0x%x, memsrc:0x%x\n", start, vaddr, secsize, memsrc);*/
+	}
+#endif
+	while (rest > 0) {
+		unsigned long read_sz;
+		memset(trunk, 0x0, TRUNK);
+		if (rest <= TRUNK) {
+			read_sz = rest;
+		} else {
+			read_sz = TRUNK;
+		}
+		memcpy(trunk, (void *)(memsrc + (sz - rest)), read_sz);
+		memcpy(buf + buf_offset, trunk, read_sz);
+
+		size_read += read_sz;
+		buf_offset += read_sz;
+		rest -= read_sz;
+	}
+
+	free(trunk);
+#ifdef MTK_3LEVEL_PAGETABLE
+	{
+		/* restore vaddr */
+		uint64_t start = ROUNDDOWN((uint64_t)data, (uint64_t)PAGE_SIZE);
+		uint32_t secsize = ROUNDUP((uint32_t)(data - start + sz), PAGE_SIZE);
+		if (start >= DRAM_PHY_ADDR) {
+			int map_ok = arch_mmu_map(vaddr, vaddr, MMU_MEMORY_TYPE_NORMAL_WRITE_BACK | MMU_MEMORY_AP_P_RW_U_NA, secsize);
+			if (map_ok != NO_ERROR) {
+				LOG("kedump: arch_mmu_map restore error: map_ok=%d, vaddr=0x%08lx in %s\n",
+					map_ok, (unsigned long)vaddr, __func__);
+			}
+		}
+	}
+#endif
+	return size_read;
+}
+
+static unsigned long long offset_plat_debug = 0;
+static unsigned long length_plat_debug = 0;
+static unsigned long long kedump_plat_write (void *data, unsigned long sz)
+{
+	unsigned long long datasize = 0;
+
+	datasize = kedump_dev_write(offset_plat_debug, (uint64_t)((uint32_t)data), sz);
+	offset_plat_debug += datasize;
+	length_plat_debug += sz;
+
+	return datasize;
+}
+
+static void kedump_dev_close(void)
+{
+	return;
+}
+
+/* the min offset reserved for the header's size. */
+static unsigned long kedump_mrdump_header_size (struct elfhdr *ehdr)
+{
+	void *phdr = PHDR_INDEX(ehdr, 1);
+	return ALIGN(PHDR_OFF(ehdr, phdr) + PHDR_SIZE(ehdr, phdr), PAGE_SIZE);
+}
+
+
+static unsigned long long kedump_dev_write_vmalloc_range(unsigned long long offset, uint64_t vaddr, uint64_t addr, unsigned long size)
+{
+	bool flag;
+	unsigned long long lcheckaddr;
+	unsigned long long lnew, hnew, hnewtmp;
+	unsigned long long vmalloc_start, vmalloc_end;
+	unsigned long long paddr, pcheckaddr;
+	int checkloop = 0;
+	unsigned long long size_wrote = 0;
+
+	/* vaddr & vadd + size are PAGE_SIZE alignment */
+	lnew = vaddr;
+	hnew = vaddr + size;
+	paddr = addr;
+	flag = true;
+
+	get_vmalloc_range(&g_mcb, &vmalloc_start, &vmalloc_end);
+	if (hnew <= lnew
+		|| !(vaddr >= vmalloc_start && vaddr + size <= vmalloc_end)) {
+		LOG("kedump: wrong range 0x%llx-0x%llx\n", lnew, hnew);
+		return 0;
+	}
+
+	if (!paddr)
+		paddr = v2p_64(lnew);
+
+	while (flag) {
+		for(checkloop = 1; checkloop < (int)((hnew - lnew) / PAGE_SIZE); checkloop++) {
+			lcheckaddr = lnew + checkloop * (unsigned long long)PAGE_SIZE;
+			pcheckaddr = v2p_64(lcheckaddr);
+			/* NOTE:
+			 * convert result should not be 0
+			 * if the result is 0 it should be the case invalid pfn pa address is recorded in kernel
+			 * */
+			if (pcheckaddr == 0 || !is_dram_address(pcheckaddr, &g_mcb)) {
+				if (pcheckaddr != 0)
+					LOG("kedump: invalid convert address:0x%llx\n", pcheckaddr);
+				LOG("kedump: convert failed expected pa:0x%llx (va:0x%llx)\n", paddr + checkloop * (unsigned long long)PAGE_SIZE, lcheckaddr);
+				continue;
+			}
+			if (pcheckaddr != (paddr + checkloop * (unsigned long long)PAGE_SIZE)) {
+				flag = false;
+				LOG("kedump: non-cont 0x%llx found(va:0x%llx, pa:0x%llx)\n", paddr + checkloop * (unsigned long long)PAGE_SIZE, lcheckaddr, pcheckaddr);
+				break;
+			}
+		}
+
+		hnewtmp = flag ? hnew : lcheckaddr;
+		size_wrote += kedump_dev_write(offset, (uint64_t)paddr, (hnewtmp - lnew));
+		offset += (hnewtmp - lnew);
+
+		if (!flag) {
+			lnew = lcheckaddr;
+			paddr = pcheckaddr;
+			flag = true;
+		} else {
+			flag = false;
+		}
+	}
+
+	return size_wrote;
+}
+
+static unsigned long long kedump_dev_write_va_32(
+		unsigned long long offset, uint64_t vaddr, unsigned long size)
+{
+	unsigned long long paddr;
+
+	paddr = v2p_32(vaddr);
+	if (paddr && is_dram_address(paddr, &g_mcb))
+		return kedump_dev_write(offset, (uint64_t)paddr, size);
+
+	LOG("kedump: 32va to pa failed 0x%llx -> 0x%llx\n", vaddr, paddr);
+	return 0;
+}
+
+static unsigned int kedump_mini_rdump(struct elfhdr *ehdr, unsigned long long offset)
+{
+	void *phdr;
+	unsigned long long addr;
+	unsigned long long vaddr;
+	unsigned long long vmalloc_start, vmalloc_end;
+	unsigned long size;
+	unsigned int i;
+	unsigned int total = 0;
+	unsigned long elfoff = kedump_mrdump_header_size(ehdr);
+	unsigned long sz_header = elfoff;
+#ifdef MTK_3LEVEL_PAGETABLE
+	{
+		uint32_t start = KE_RESERVED_MEM_ADDR;
+		/* KEDump need to use header in DRAZM, we must allocate it first */
+		arch_mmu_map(ROUNDDOWN((uint64_t)start, PAGE_SIZE), ROUNDDOWN((uint32_t)start, PAGE_SIZE),
+		             MMU_MEMORY_TYPE_NORMAL_WRITE_BACK | MMU_MEMORY_AP_P_RW_U_NA, ROUNDUP(sz_header, PAGE_SIZE));
+	}
+#endif
+	for (i = 0; i < ehdr->e_phnum; i++) {
+		phdr = PHDR_INDEX(ehdr, i);
+		if (PHDR_SIZE(ehdr, phdr) != 0 || PHDR_TYPE(ehdr, phdr) != 0)
+			LOGD("kedump: PT[%d] %llx@%llx -> %llx(%llx)\n", PHDR_TYPE(ehdr, phdr), (uint64_t)PHDR_SIZE(ehdr, phdr), (uint64_t)PHDR_ADDR(ehdr, phdr), (uint64_t)elfoff, (uint64_t)PHDR_OFF(ehdr, phdr));
+		if (PHDR_TYPE(ehdr, phdr) != PT_LOAD)
+			continue;
+		if (PHDR_MEMSZ(ehdr, phdr) != 0 ||
+		    PHDR_FLAGS(ehdr, phdr) != 0 ||
+		    PHDR_ALIGN(ehdr, phdr) != 0) {
+			LOG("memory check fail: memsz-0x%llx, flags-0x%x, align-0x%llx\n",
+					PHDR_MEMSZ(ehdr, phdr),
+					PHDR_FLAGS(ehdr, phdr),
+					PHDR_ALIGN(ehdr, phdr));
+			break; /* stop dumping minirdump */
+		}
+		addr = PHDR_ADDR(ehdr, phdr);
+		vaddr = PHDR_VADDR(ehdr, phdr);
+
+		size = PHDR_SIZE(ehdr, phdr);
+		if (size == 0 || elfoff == 0)
+			LOG("kedump: dump addr 0x%llx, size 0x%lx\n", addr, size);
+		if (ehdr->e_machine == EM_ARM)
+			((struct elf32_phdr*)phdr)->p_offset = elfoff;
+		else
+			((struct elf64_phdr*)phdr)->p_offset = elfoff;
+
+		if (size != 0 && elfoff != 0) {
+			/* LOG("kedump: start:0x%llx-0x%llx\n", vaddr, vaddr + size); */
+			/*
+			 * 1.|start...end|...|vmalloc_start...vmalloc_end|
+			 *
+			 * 2.|vmalloc_start...vmalloc_end|...|start...end|
+			 *
+			 * 3.|vmalloc_start...|start...end|...vmalloc_end|
+			 *
+			 * 4.|vmalloc_start...|start...vmalloc_end|...end|
+			 *
+			 * 5.|start...|vmalloc_start...end|...vmalloc_end|
+			 *
+			 * 6.|start...|vmalloc_start...vmalloc_end|...end|
+			 */
+			get_vmalloc_range(&g_mcb, &vmalloc_start, &vmalloc_end);
+			if (!is_arm_32bit(&g_mcb, vaddr)
+				&& (vaddr >= vmalloc_start) && (vaddr + size <= vmalloc_end)) {
+				/* LOG("kedump: overlapp case: 3\n"); */
+				total += kedump_dev_write_vmalloc_range(offset + elfoff, vaddr, addr, size);
+			} else if (is_arm_32bit(&g_mcb, vaddr)) {
+				if (addr)
+					total += kedump_dev_write(offset + elfoff, (uint64_t)addr, size);
+				else
+					total += kedump_dev_write_va_32(offset + elfoff, vaddr, size);
+			} else {
+				if ((vaddr + size <= vmalloc_start) || (vaddr >= vmalloc_end)) {
+					/* LOG("kedump: normal no-overlapp case: %d\n", (vaddr + size <= vmalloc_start) ? 1 : 2); */
+				} else if ((vaddr <= vmalloc_start) && (vaddr + size >= vmalloc_end)) {
+					/* not expected max size for mini rdump load is smaller than vmalloc */
+					LOG("kedump: never overlapp case: 6\n");
+				} else if ((vaddr + size <= vmalloc_end) || (vaddr >= vmalloc_start)) {
+					/* not expected cases */
+					LOG("kedump: should not be overlapp case: %d\n", (vaddr + size <= vmalloc_end) ? 5 : 4);
+				}
+				if (!addr)
+					addr = v2p_64(vaddr);
+				if (!addr)
+					LOG("kedump: convert fail va 0x%llx, size 0x%lx\n", vaddr, size);
+				total += kedump_dev_write(offset + elfoff, (uint64_t)addr, size);
+			}
+		}
+		elfoff += size;
+	}
+	total += kedump_dev_write(offset, (uint64_t)((uint32_t)ehdr->start), sz_header);
+	LOG("kedump: writed size 0x%x\n", total);
+	return (unsigned int)elfoff;
+}
+
+static unsigned int kedump_misc(unsigned long long addr, unsigned int start, unsigned int size, unsigned long long offset)
+{
+	unsigned int total;
+	LOG("kedump: misc data %x@%llx+%x\n", size, addr, start);
+	if (start >= size)
+		start = start % size;
+	total = kedump_dev_write(offset, (uint64_t)(addr + start), size - start);
+	if (start)
+		total += kedump_dev_write(offset + total, (uint64_t)addr, start);
+	return total;
+}
+
+static unsigned int kedump_misc32(struct mrdump_mini_misc_data32 *data, unsigned long long offset)
+{
+	unsigned int addr = data->paddr;
+	unsigned int start = 0;
+	unsigned int size = data->size;
+	if (data->start != 0)
+		kedump_mem_read(data->start, sizeof(unsigned int), &start);
+	else
+		start = 0;
+	return kedump_misc((uint64_t)((uint32_t)addr), start, size, offset);
+}
+
+static unsigned int kedump_misc64(struct mrdump_mini_misc_data64 *data, unsigned long long offset)
+{
+	unsigned long long addr = (unsigned long long)data->paddr;
+	unsigned int start = 0;
+	unsigned int size = (unsigned int)data->size;
+	if (data->start != 0)
+		kedump_mem_read(data->start, sizeof(unsigned int), &start);
+	else
+		start = 0;
+	return kedump_misc(addr, start, size, offset);
+}
+
+struct ipanic_header panic_header;
+static unsigned long long header_off;
+static void kedump_add2hdr(unsigned int offset, unsigned int size, unsigned datasize, char *name)
+{
+	struct ipanic_data_header *pdata;
+	int i;
+	for (i = 0; i < IPANIC_NR_SECTIONS; i++) {
+		pdata = &panic_header.data_hdr[i];
+		if (pdata->valid == 0)
+			break;
+	}
+	LOG("kedump add: %s[%d] %x/%x@%x\n", name, i, datasize, size, offset);
+	if (i < IPANIC_NR_SECTIONS) {
+		pdata->offset = offset;
+		pdata->total = size;
+		pdata->used = datasize;
+		strlcpy((char*)pdata->name, name, sizeof(pdata->name));
+		pdata->valid = 1;
+	}
+	header_off += kedump_dev_write(header_off, (uint64_t)((uint32_t)(pdata)), sizeof(struct ipanic_data_header));
+}
+
+static int kedump_kernel_info(unsigned long long *offset)
+{
+	struct elfhdr *ehdr;
+	unsigned long sz_misc;
+	void *phdr_misc, *phdr_pspr;
+	struct elf_note *misc, *miscs;
+	char *m_name;
+	void *m_data;
+	char name[32];
+	unsigned int size, datasize;
+	unsigned int i;
+
+	ehdr = kedump_elf_hdr();
+	if (0 == ehdr)
+		return -1;
+	ram_console_set_dump_step(AEE_LKDUMP_MINI_RDUMP);
+	datasize = kedump_mini_rdump(ehdr, *offset);
+	size = datasize;
+	kedump_add2hdr(*offset, size, datasize, "SYS_MINI_RDUMP");
+	*offset += datasize;
+
+	phdr_pspr = PHDR_INDEX(ehdr, 0);
+	phdr_misc = PHDR_INDEX(ehdr, 1);
+	if (PHDR_OFF(ehdr, phdr_misc) != PHDR_OFF(ehdr, phdr_pspr) + PHDR_SIZE(ehdr, phdr_pspr)) {
+		LOG("first 2 ehdr invalid\n");
+		return -1;
+	}
+	miscs = (struct elf_note*)(ehdr->start + PHDR_OFF(ehdr, phdr_misc));
+	LOGD("kedump: misc[%p] %llx@%llx\n", phdr_misc, PHDR_SIZE(ehdr, phdr_misc), PHDR_OFF(ehdr, phdr_misc));
+	sz_misc = sizeof(struct elf_note) + miscs->n_namesz + miscs->n_descsz;
+	LOG("kedump: miscs[%p], size %lx\n", miscs, sz_misc);
+	for (i = 0; i < (PHDR_SIZE(ehdr, phdr_misc)) / sz_misc; i++) {
+		char klog_first[16];
+		unsigned int start_tmp = 0;
+		memset(klog_first, 0x0, sizeof(klog_first));
+		misc = (struct elf_note*)((void*)miscs + sz_misc * i);
+		m_name = (char*)misc + sizeof(struct elf_note);
+		if (m_name[0] == 'N' && m_name[1] == 'A' && m_name[2] == '\0')
+			break;
+		if (misc->n_type != NT_IPANIC_MISC) {
+			LOG("misc invalid type: 0x%x\n", misc->n_type);
+			break;
+		}
+		m_data = (void*)misc + sizeof(struct elf_note) + misc->n_namesz;
+		if (misc->n_descsz == sizeof(struct mrdump_mini_misc_data32)) {
+			if (strcmp(m_name, "_KERNEL_LOG_") == 0) {
+				if (((struct mrdump_mini_misc_data32*)m_data)->start != 0)
+					kedump_mem_read(((struct mrdump_mini_misc_data32*)m_data)->start, sizeof(unsigned int), &start_tmp);
+				else
+					start_tmp = 0;
+				sprintf(klog_first, "_%u", start_tmp);
+				((struct mrdump_mini_misc_data32*)m_data)->start = 0;
+			}
+			datasize = kedump_misc32((struct mrdump_mini_misc_data32*)m_data, *offset);
+			size = ((struct mrdump_mini_misc_data32*)m_data)->size;
+		} else {
+			if (strcmp(m_name, "_KERNEL_LOG_") == 0) {
+				if (((struct mrdump_mini_misc_data64*)m_data)->start != 0)
+					kedump_mem_read(((struct mrdump_mini_misc_data64*)m_data)->start, sizeof(unsigned int), &start_tmp);
+				else
+					start_tmp = 0;
+				sprintf(klog_first, "_%u", start_tmp);
+				((struct mrdump_mini_misc_data64*)m_data)->start = 0;
+			}
+			datasize = kedump_misc64((struct mrdump_mini_misc_data64*)m_data, *offset);
+			size = ((struct mrdump_mini_misc_data64*)m_data)->size;
+		}
+		/* [SYS_]MISC[_RAW] */
+		if (m_name[0] == '_')
+			strlcpy (name, "SYS", sizeof(name));
+		else
+			name[0] = 0;
+		strlcat (name, m_name, sizeof(name));
+		if (m_name[strlen(m_name)-1] == '_')
+			strlcat (name,  "RAW", sizeof(name));
+		if (klog_first[0] != 0)
+			strlcat(name, klog_first, sizeof(name));
+		kedump_add2hdr(*offset, size, datasize, name);
+		*offset += datasize;
+	}
+	return 0;
+}
+
+static int kedump_ram_console(unsigned long long *offset)
+{
+	unsigned int sz_misc = 0, addr_misc = 0;
+	unsigned int datasize;
+
+	/* ram_console raw log */
+	ram_console_set_dump_step(AEE_LKDUMP_RAMCONSOLE_RAW);
+	ram_console_addr_size(&addr_misc, &sz_misc);
+	if (addr_misc && sz_misc) {
+		datasize = kedump_misc(addr_misc, 0, sz_misc, *offset);
+		kc.ram_console_crc = calculate_crc32((void *)addr_misc, sz_misc);
+		kedump_add2hdr(*offset, sz_misc, datasize, "SYS_RAMCONSOLE_RAW");
+		*offset += datasize;
+	}
+#ifdef MTK_PMIC_FULL_RESET
+	/* pstore raw log*/
+	ram_console_set_dump_step(AEE_LKDUMP_PSTORE_RAW);
+	addr_misc = 0;
+	sz_misc = 0;
+	pstore_addr_size(&addr_misc, &sz_misc);
+
+	if (addr_misc && sz_misc) {
+		datasize = kedump_misc(addr_misc, 0, sz_misc, *offset);
+#ifdef MTK_3LEVEL_PAGETABLE
+		{
+			/*int ret;*/
+			uint32_t start = ROUNDDOWN((uint32_t)addr_misc, PAGE_SIZE);
+			uint32_t secsize = ROUNDUP(((uint32_t)sz_misc), PAGE_SIZE);
+			if (start >= DRAM_PHY_ADDR) {
+				/* minirdump: minirdump will dump memory in DRAM, we must allocate it first */
+				arch_mmu_map((uint64_t) start, start,
+						MMU_MEMORY_TYPE_NORMAL_WRITE_BACK | MMU_MEMORY_AP_P_RW_U_NA, secsize);
+			}
+		}
+#endif
+		kc.pstore_crc = calculate_crc32((void *)addr_misc, sz_misc);
+		kedump_add2hdr(*offset, sz_misc, datasize, "SYS_PSTORE_RAW");
+		*offset += datasize;
+	}
+#endif
+	/* save crc data*/
+	ram_console_set_dump_step(AEE_LKDUMP_KEDUMP_CRC);
+	datasize = kedump_dev_write(*offset, (uint64_t)((uint32_t)(&kc)), sizeof(struct kedump_crc));
+	kedump_add2hdr(*offset, sizeof(struct kedump_crc), datasize, "KEDUMP_CRC");
+	*offset += datasize;
+	return 0;
+}
+
+static int kedump_platform_debug(unsigned long long *offset)
+{
+	/* platform debug */
+	int len = 0;
+	unsigned int datasize;
+	unsigned int i;
+
+	for (i=0; i<AEE_PLAT_DEBUG_NUM; i++) {
+		offset_plat_debug = *offset;
+		length_plat_debug = 0;
+		if (adfi[i].filesize > 0) {
+			ram_console_set_dump_step(adfi[i].step);
+			datasize = kedump_plat_savelog(i, offset_plat_debug, &len, kedump_plat_write);
+			if (datasize > adfi[i].filesize)
+				length_plat_debug = datasize = adfi[i].filesize;
+			if (datasize > 0) {
+				kedump_add2hdr(*offset, length_plat_debug, datasize, adfi[i].filename);
+				*offset += datasize;
+			} else {
+				LOG("kedump: adfi no %d\n", i);
+			}
+		}
+	}
+	return 0;
+}
+
+static int kedump_to_expdb(void)
+{
+	unsigned long long offset;
+	unsigned int datasize;
+	part_dev_t *part_dev;
+
+	part_dev = mt_part_get_device();
+
+	if (!part_dev || !part_dev->blkdev) {
+		LOG("kedump: device get error, dev:%p\n", part_dev);
+		return -1;
+	}
+
+	if (kedump_dev_open() != 0)
+		return -1;
+
+	last_dump_step = ram_console_get_dump_step();
+	if (last_dump_step != AEE_LKDUMP_CLEAR) {
+		LOG("kedump: last lk dump is not finished at step %u\n", last_dump_step);
+		return 0;
+	}
+#if defined(MTK_MLC_NAND_SUPPORT) || defined(MTK_TLC_NAND_SUPPORT)
+	mem_expdb = malloc(MEM_EXPDB_SIZE);
+	if (mem_expdb == NULL) {
+		LOG("mem_expdb malloc fail!\n");
+		return -1;
+	}
+	LOG("mem_expdb malloc success, 0x%x size is 0x%x\n", mem_expdb, MEM_EXPDB_SIZE);
+	memset(mem_expdb, 0x0, MEM_EXPDB_SIZE);
+#endif
+	//write header firstly
+	panic_header.magic = AEE_IPANIC_MAGIC;
+	panic_header.version = AEE_IPANIC_PHDR_VERSION;
+	panic_header.size = sizeof(panic_header);
+	panic_header.blksize = part_dev->blkdev->blksz;
+	panic_header.partsize = dev.part_size;
+	kedump_dev_write(0, (uint64_t)((uint32_t)(&panic_header)), sizeof(panic_header));
+	header_off = sizeof(panic_header) - sizeof(struct ipanic_data_header) * IPANIC_NR_SECTIONS;
+
+	LOG("kedump: block size:0x%lx\n", part_dev->blkdev->blksz);
+	/* reserve space in expdb for panic header */
+	offset = ALIGN(sizeof(panic_header), part_dev->blkdev->blksz);
+
+	kedump_ram_console(&offset);
+	kedump_kernel_info(&offset);
+	kedump_platform_debug(&offset);
+
+	/* save KEdump flow logs */
+	datasize = kedump_dev_write(offset, (uint64_t)(uint32_t)logbuf, SZLOG);
+	kedump_add2hdr(offset, SZLOG, datasize, "ZAEE_LOG");
+	offset += datasize;
+
+#if defined(MTK_MLC_NAND_SUPPORT) || defined(MTK_TLC_NAND_SUPPORT)
+	unsigned long long size_wrote = dev.dev->write(dev.dev, mem_expdb, (unsigned long)dev.ptn, MEM_EXPDB_SIZE/*dev.part_size*/, dev.part_id);
+	free(mem_expdb);
+#endif
+	ram_console_set_dump_step(AEE_LKDUMP_CLEAR);
+	return 0;
+}
+
+static int kedump_restore_mem(void)
+{
+	int i;
+	struct ipanic_header iheader;
+	struct kedump_crc saved_crc = {0, 0};
+	unsigned int crc;
+	unsigned int sz_misc = 0, addr_misc = 0;
+	unsigned int sz_misc_pstore = 0, addr_misc_pstore = 0;
+	unsigned char *temp_ram_console = NULL;
+#ifdef MTK_PMIC_FULL_RESET
+	unsigned char *temp_pstore = NULL;
+#endif
+	if (kedump_dev_open() != 0)
+		return -1;
+
+	dev.dev->read(dev.dev, dev.ptn, (unsigned char *)&iheader, sizeof(struct ipanic_header), dev.part_id);
+	if (iheader.magic == AEE_IPANIC_MAGIC && iheader.version >= AEE_IPANIC_PHDR_VERSION) {
+		LOG("kedump: found content in expdb\n");
+		for (i = IPANIC_NR_SECTIONS - 1; i >= 0; i--) {
+			if (strncmp((const char *)iheader.data_hdr[i].name, "KEDUMP_CRC", sizeof("KEDUMP_CRC") - 1) == 0) {
+				LOG("kedump: read %s from offset 0x%x size 0x%x\n", iheader.data_hdr[i].name, iheader.data_hdr[i].offset, iheader.data_hdr[i].used);
+				dev.dev->read(dev.dev, dev.ptn + iheader.data_hdr[i].offset, (uchar *)(&saved_crc), iheader.data_hdr[i].used, dev.part_id);
+			}
+			if (strncmp((const char *)iheader.data_hdr[i].name, "SYS_RAMCONSOLE_RAW", sizeof("SYS_RAMCONSOLE_RAW") - 1) == 0) {
+				ram_console_addr_size(&addr_misc, &sz_misc);
+				if (addr_misc != 0 && sz_misc != 0) {
+					temp_ram_console = malloc(sz_misc);
+					if (!temp_ram_console) {
+						LOG("kedump: temp ram_console alloc fail\n");
+					} else {
+						LOG("kedump: read %s from offset 0x%x size 0x%x\n", iheader.data_hdr[i].name, iheader.data_hdr[i].offset, iheader.data_hdr[i].used);
+						memset(temp_ram_console, 0x0, sz_misc);
+						//dev.dev->read(dev.dev, dev.ptn + iheader.data_hdr[i].offset, (uchar *)addr_misc, iheader.data_hdr[i].used, dev.part_id);
+						dev.dev->read(dev.dev, dev.ptn + iheader.data_hdr[i].offset, temp_ram_console, iheader.data_hdr[i].used, dev.part_id);
+						crc = calculate_crc32(temp_ram_console, sz_misc);
+						if (crc != saved_crc.ram_console_crc) {
+							LOG("kedump: temp ram_console crc fail\n");
+							free(temp_ram_console);
+							temp_ram_console = NULL;
+						}
+					}
+				} else {
+					LOG("kedump: ram_console not init\n");
+				}
+			}
+#ifdef MTK_PMIC_FULL_RESET
+			else if (strncmp((const char *)iheader.data_hdr[i].name, "SYS_PSTORE_RAW", sizeof("SYS_PSTORE_RAW") - 1) == 0) {
+				pstore_addr_size(&addr_misc_pstore, &sz_misc_pstore);
+				if (addr_misc_pstore == 0 || sz_misc_pstore == 0)
+					continue;
+
+#ifdef MTK_3LEVEL_PAGETABLE
+				{
+					/*int ret;*/
+					uint32_t start = ROUNDDOWN((uint32_t)addr_misc_pstore, PAGE_SIZE);
+					uint32_t secsize = ROUNDUP(((uint32_t)sz_misc_pstore), PAGE_SIZE);
+					if (start >= DRAM_PHY_ADDR) {
+						/* minirdump: minirdump will dump memory in DRAM, we must allocate it first */
+						arch_mmu_map((uint64_t) start, start,
+								MMU_MEMORY_TYPE_NORMAL_WRITE_BACK | MMU_MEMORY_AP_P_RW_U_NA, secsize);
+					}
+				}
+#endif
+				temp_pstore = malloc(sz_misc_pstore);
+				if (!temp_pstore) {
+					LOG("kedump: temp pstore alloc fail\n");
+				} else {
+					LOG("kedump: read %s from offset 0x%x size 0x%x\n", iheader.data_hdr[i].name, iheader.data_hdr[i].offset, iheader.data_hdr[i].used);
+					memset(temp_pstore, 0x0, sz_misc_pstore);
+					//dev.dev->read(dev.dev, dev.ptn + iheader.data_hdr[i].offset, (uchar *)addr_misc_pstore, iheader.data_hdr[i].used, dev.part_id);
+					dev.dev->read(dev.dev, dev.ptn + iheader.data_hdr[i].offset, temp_pstore, iheader.data_hdr[i].used, dev.part_id);
+					crc = calculate_crc32(temp_pstore, sz_misc_pstore);
+					if (crc != saved_crc.pstore_crc) {
+						LOG("kedump: temp pstore crc fail\n");
+						free(temp_pstore);
+						temp_pstore = NULL;
+					}
+				}
+			}
+#endif
+		}
+
+		if (ram_console_should_restore(temp_ram_console)) {
+			LOG("kedump: ram_console_should_restore\n");
+			memcpy((uchar *)addr_misc, temp_ram_console, sz_misc);
+#ifdef MTK_PMIC_FULL_RESET
+			if (temp_pstore)
+				memcpy((uchar *)addr_misc_pstore, temp_pstore, sz_misc_pstore);
+#endif
+			ram_console_set_dump_step(AEE_LKDUMP_CLEAR);
+			ram_console_is_abnormal_boot();
+		}
+
+		if (temp_ram_console)
+			free(temp_ram_console);
+#ifdef MTK_PMIC_FULL_RESET
+		if (temp_pstore)
+			free(temp_pstore);
+#endif
+	}
+	return 0;
+}
+
+static int kedump_skip(void)
+{
+	unsigned int boot_reason = g_boot_arg->boot_reason;
+	static int kedump_dumped = 0;
+	LOG("kedump: boot_reason(%d)\n", boot_reason);
+	ram_console_init();
+	/* this flow should be executed once only */
+	if (kedump_dumped == 0) {
+		kedump_dumped = 1;
+		if (ram_console_is_abnormal_boot())
+			return 0;
+	}
+
+#ifdef MTK_PMIC_FULL_RESET
+	//if this reboot is full pmic reset, then restore the memory of ram_console and pstore
+	if (ram_console_reboot_by_cold_reset()) {
+		LOG("kedump: last is full pmic reset!\n");
+		kedump_restore_mem();
+		return 1;
+	} else {
+		LOG("kedump: last is not full pmic reset!\n");
+	}
+#endif
+
+	// for power lost or reboot before KE DB collected scenario
+	kedump_restore_mem();
+
+	return 1;
+}
+
+static int kedump_avail(void)
+{
+#ifdef MTK_3LEVEL_PAGETABLE
+	vaddr_t vaddr = (vaddr_t)target_get_scratch_address();
+	LOG("kedump: address:0x%lx, page size:0x%x\n", vaddr, PAGE_SIZE);
+	{
+		uint32_t start = KE_RESERVED_MEM_ADDR;
+		/* KEDump need to use header in DRAZM, we must allocate it first */
+		arch_mmu_map(ROUNDDOWN((uint64_t)start, PAGE_SIZE), ROUNDDOWN((uint32_t)start, PAGE_SIZE),
+		             MMU_MEMORY_TYPE_NORMAL_WRITE_BACK | MMU_MEMORY_AP_P_RW_U_NA, ROUNDUP(sizeof(struct elfhdr), PAGE_SIZE));
+	}
+#endif
+	void *flag = (void *)(KE_RESERVED_MEM_ADDR);
+
+	if (((char *)flag)[0] == 0x81 && ((char *)flag)[1] == 'E' && ((char *)flag)[2] == 'L' && ((char *)flag)[3] == 'F') {
+		LOG("kedump: already dumped in lk\n");
+		return -1;
+	}
+
+	if (((char *)flag)[0] == 0x0 && ((char *)flag)[1] == 'E' && ((char *)flag)[2] == 'L' && ((char *)flag)[3] == 'F') {
+		LOG("kedump: already dumped in kernel\n");
+		return -1;
+	}
+	/*
+	 * read boot image first for determine kernel
+	 * is 32 bit or 64 bit
+	 */
+	load_bootimg_hdr(BOOTIMG_TYPE_BOOT);
+	return 0;
+}
+
+int kedump_get_data_info(int index, char **name, u32 *offset, u32 *size)
+{
+	struct ipanic_header iheader;
+	struct ipanic_data_header *pdata;
+
+	if (kedump_dev_open() != 0)
+		return -1;
+	dev.dev->read(dev.dev, dev.ptn, (unsigned char *)&iheader, sizeof(struct ipanic_header), dev.part_id);
+	if (iheader.magic != AEE_IPANIC_MAGIC || iheader.version < AEE_IPANIC_PHDR_VERSION)
+		return -2;
+
+	if (index < 0 || index >= IPANIC_NR_SECTIONS) {
+		LOG("kedump: invalid index number:%d\n", index);
+		return -3;
+	}
+
+	if (name == NULL || offset == NULL || size == NULL) {
+		LOG("kedump: invalid argument number:%d\n", index);
+		return -4;
+	}
+
+	pdata = &iheader.data_hdr[index];
+	if (pdata->valid == 0)
+		return -5;
+
+	*name = (char *)pdata->name;
+	*offset = pdata->offset;
+	*size = pdata->used;
+
+	return 0;
+}
+
+static int kedump_done(void)
+{
+	void *flag = (void *)(KE_RESERVED_MEM_ADDR);
+
+	((char *)flag)[0] = 0x81;
+	((char *)flag)[1] = 'E';
+	((char *)flag)[2] = 'L';
+	((char *)flag)[3] = 'F';
+	arch_clean_cache_range((addr_t)KE_RESERVED_MEM_ADDR, sizeof(struct elfhdr));
+	return 0;
+}
+
+/* in case that platform didn't support smart_reset_check() */
+const char *smart_reset_check(void) __attribute__((weak));
+const char *smart_reset_check(void)
+{
+	return NULL;
+}
+
+/* in case that platform didn't support mtk_wdt_get_last_stage() */
+const char *mtk_wdt_get_last_stage(void) __attribute__((weak));
+const char *mtk_wdt_get_last_stage(void)
+{
+	return NULL;
+}
+
+#define SHOW_ARGS(p, a, b, c, d) \
+	LOG(#a":0x%llx, "#b":0x%llx,"#c":0x%llx, "#d":0x%llx\n", (p)->a, (p)->b, (p)->c, (p)->d)
+static void show_info(struct mrdump_control_block *mcb)
+{
+	if (mcb == NULL) {
+		LOG("%s: mrdump_cb is NULL\n", __func__);
+		return;
+	}
+
+	if (memcmp(mcb->sig, MRDUMP_GO_DUMP, 8) == 0) {
+		struct mrdump_machdesc *mmp = &mcb->machdesc;
+		SHOW_ARGS(mmp, vmalloc_start, vmalloc_end, master_page_table, high_memory);
+	} else {
+		LOG("mrdump_cb: sig error:0x%llx in %s\n", *(uint64_t *)mcb, __func__);
+		return;
+	}
+}
+
+extern BOOT_ARGUMENT *g_boot_arg;
+/* Dump KE infomation to expdb */
+/*  1: has expception, 0: has no exception */
+int kedump_mini(void)
+{
+	const char *status;
+	struct rtc_time tm;
+
+	if (!read_kedump_config()) {
+		LOG("kedump: disable\n");
+		return 0;
+	}
+
+	status = smart_reset_check();
+	if (status != NULL)
+		LOG("%s\n", status);
+
+	status = mtk_wdt_get_last_stage();
+	if (status != NULL)
+		LOG("%s\n", status);
+
+	LOG("kedump mini start\n");
+
+	rtc_get_time(&tm);
+	LOG("kedump: current time: [%d/%d/%d %d:%d:%d]\n", tm.tm_year, tm.tm_mon, tm.tm_mday, tm.tm_hour, tm.tm_min, tm.tm_sec);
+	if (g_boot_arg) {
+		if (!g_boot_arg->ddr_reserve_enable)
+			LOG("kedump: ddr reserve mode disabled\n");
+		else
+			LOG("kedump: ddr reserve mode enabled\n");
+		if (!g_boot_arg->ddr_reserve_success)
+			LOG("kedump: ddr reserve mode failed\n");
+	} else {
+		LOG("kedump: null boot arg pointer error\n");
+	}
+
+	if (lkdump_debug_init())
+		LOG("kedump: lkdump debug init ok\n");
+	else
+		LOG("kedump: lkdump debug not ready\n");
+
+	if (kedump_skip())
+		return 0;
+
+	if (kedump_avail())
+		return 0;
+
+	aee_mrdump_get_info(&g_mcb);
+	show_info(&g_mcb);
+
+	kedump_to_expdb();
+
+	kedump_done();
+	LOG("kedump mini done\n");
+	return 1;
+}

+ 150 - 0
app/mt_boot/aee/KEHeader.h

@@ -0,0 +1,150 @@
+/* Copyright Statement:
+*
+* This software/firmware and related documentation ("MediaTek Software") are
+* protected under relevant copyright laws. The information contained herein
+* is confidential and proprietary to MediaTek Inc. and/or its licensors.
+* Without the prior written permission of MediaTek inc. and/or its licensors,
+* any reproduction, modification, use or disclosure of MediaTek Software,
+* and information contained herein, in whole or in part, shall be strictly prohibited.
+*/
+/* MediaTek Inc. (C) 2016. All rights reserved.
+*
+* BY OPENING THIS FILE, RECEIVER HEREBY UNEQUIVOCALLY ACKNOWLEDGES AND AGREES
+* THAT THE SOFTWARE/FIRMWARE AND ITS DOCUMENTATIONS ("MEDIATEK SOFTWARE")
+* RECEIVED FROM MEDIATEK AND/OR ITS REPRESENTATIVES ARE PROVIDED TO RECEIVER ON
+* AN "AS-IS" BASIS ONLY. MEDIATEK EXPRESSLY DISCLAIMS ANY AND ALL WARRANTIES,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED WARRANTIES OF
+* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE OR NONINFRINGEMENT.
+* NEITHER DOES MEDIATEK PROVIDE ANY WARRANTY WHATSOEVER WITH RESPECT TO THE
+* SOFTWARE OF ANY THIRD PARTY WHICH MAY BE USED BY, INCORPORATED IN, OR
+* SUPPLIED WITH THE MEDIATEK SOFTWARE, AND RECEIVER AGREES TO LOOK ONLY TO SUCH
+* THIRD PARTY FOR ANY WARRANTY CLAIM RELATING THERETO. RECEIVER EXPRESSLY ACKNOWLEDGES
+* THAT IT IS RECEIVER'S SOLE RESPONSIBILITY TO OBTAIN FROM ANY THIRD PARTY ALL PROPER LICENSES
+* CONTAINED IN MEDIATEK SOFTWARE. MEDIATEK SHALL ALSO NOT BE RESPONSIBLE FOR ANY MEDIATEK
+* SOFTWARE RELEASES MADE TO RECEIVER'S SPECIFICATION OR TO CONFORM TO A PARTICULAR
+* STANDARD OR OPEN FORUM. RECEIVER'S SOLE AND EXCLUSIVE REMEDY AND MEDIATEK'S ENTIRE AND
+* CUMULATIVE LIABILITY WITH RESPECT TO THE MEDIATEK SOFTWARE RELEASED HEREUNDER WILL BE,
+* AT MEDIATEK'S OPTION, TO REVISE OR REPLACE THE MEDIATEK SOFTWARE AT ISSUE,
+* OR REFUND ANY SOFTWARE LICENSE FEES OR SERVICE CHARGE PAID BY RECEIVER TO
+* MEDIATEK FOR SUCH MEDIATEK SOFTWARE AT ISSUE.
+*/
+
+typedef  unsigned int u32;
+typedef  unsigned char u8;
+typedef  unsigned long long u64;
+
+#define AEE_IPANIC_PLABLE "expdb"
+
+
+#define AEE_IPANIC_MAGIC 0xaee0dead
+#define AEE_IPANIC_PHDR_VERSION     0x10
+#define IPANIC_NR_SECTIONS              64
+#if (AEE_IPANIC_PHDR_VERSION >= 0x10)
+#define IPANIC_USERSPACE_READ           1
+#endif
+
+/***************************************************************/
+/* #define MRDUMP_MINI_NR_SECTION       40         */
+/* #define MRDUMP_MINI_SECTION_SIZE     (32 * 1024)            */
+/* #define MRDUMP_MINI_NR_MISC      20             */
+/***************************************************************/
+
+struct mrdump_mini_misc_data32 {
+	unsigned int vaddr;
+	unsigned int paddr;
+	unsigned int start;
+	unsigned int size;
+};
+
+struct mrdump_mini_misc_data64 {
+	unsigned long long vaddr;
+	unsigned long long paddr;
+	unsigned long long start;
+	unsigned long long size;
+};
+
+/**********************************************/
+/* struct mrdump_mini_elf_misc {          */
+/*         struct elf_note note;          */
+/*         char name[16];             */
+/*         struct mrdump_mini_misc_data data; */
+/* };                         */
+/**********************************************/
+
+/**********************************************************/
+/* struct mrdump_mini_elf_header {            */
+/*         struct elfhdr ehdr;                */
+/*         struct elf_phdr phdrs[MRDUMP_MINI_NR_SECTION]; */
+/*         struct {                   */
+/*                 struct elf_note note;          */
+/*                 char name[12];             */
+/*                 struct elf_prpsinfo data;          */
+/*         } psinfo;                      */
+/*         struct {                   */
+/*                 struct elf_note note;          */
+/*                 char name[12];             */
+/*                 struct elf_prstatus data;          */
+/*         } prstatus[3];                 */
+/*         struct {                   */
+/*                 struct elf_note note;          */
+/*                 char name[20];             */
+/*                 struct mrdump_mini_misc_data data;     */
+/*         } misc[MRDUMP_MINI_NR_MISC];           */
+/* };                             */
+/**********************************************************/
+
+#define PAGE_SIZE 4096
+/***********************************************************************************************************/
+/* #define MRDUMP_MINI_HEADER_SIZE  ALIGN(sizeof(struct mrdump_mini_elf_header), PAGE_SIZE)        */
+/* #define MRDUMP_MINI_DATA_SIZE        (MRDUMP_MINI_NR_SECTION * MRDUMP_MINI_SECTION_SIZE)        */
+/* #define MRDUMP_MINI_BUF_SIZE         (MRDUMP_MINI_HEADER_SIZE + MRDUMP_MINI_DATA_SIZE)      */
+/***********************************************************************************************************/
+
+// ipanic partation
+struct ipanic_data_header {
+	u32 type;       /* data type(0-31) */
+	u32 valid;      /* set to 1 when dump succeded */
+	u32 offset;     /* offset in EXPDB partition */
+	u32 used;       /* valid data size */
+	u32 total;      /* allocated partition size */
+	u32 encrypt;    /* data encrypted */
+	u32 raw;        /* raw data or plain text */
+	u32 compact;    /* data and header in same block, to save space */
+	u8 name[32];
+};
+
+struct ipanic_header {
+	u32 magic;
+	u32 version;    /* ipanic version */
+	u32 size;       /* ipanic_header size */
+	u32 datas;      /* bitmap of data sections dumped */
+	u32 dhblk;      /* data header blk size, 0 if no dup data headers */
+	u32 blksize;
+	u32 partsize;   /* expdb partition totoal size */
+	u32 bufsize;
+	u64 buf;
+	struct ipanic_data_header data_hdr[IPANIC_NR_SECTIONS];
+};
+
+#define IPANIC_MMPROFILE_LIMIT          0x220000
+
+typedef enum {
+	IPANIC_DT_HEADER = 0 ,
+	IPANIC_DT_KERNEL_LOG = 1 ,
+	IPANIC_DT_WDT_LOG ,
+	IPANIC_DT_WQ_LOG ,
+	IPANIC_DT_CURRENT_TSK = 6 ,
+	IPANIC_DT_OOPS_LOG ,
+	IPANIC_DT_MINI_RDUMP = 8 ,
+	IPANIC_DT_MMPROFILE ,
+	IPANIC_DT_MAIN_LOG ,
+	IPANIC_DT_SYSTEM_LOG ,
+	IPANIC_DT_EVENTS_LOG ,
+	IPANIC_DT_RADIO_LOG ,
+	IPANIC_DT_LAST_LOG ,
+	IPANIC_DT_RAM_DUMP = 28 ,
+	IPANIC_DT_SHUTDOWN_LOG = 30 ,
+	IPANIC_DT_RESERVED31 = 31 ,
+} IPANIC_DT;
+
+int kedump_get_data_info(int index, char **name, u32 *offset, u32 *size);

+ 708 - 0
app/mt_boot/aee/aee.c

@@ -0,0 +1,708 @@
+/* Copyright Statement:
+*
+* This software/firmware and related documentation ("MediaTek Software") are
+* protected under relevant copyright laws. The information contained herein
+* is confidential and proprietary to MediaTek Inc. and/or its licensors.
+* Without the prior written permission of MediaTek inc. and/or its licensors,
+* any reproduction, modification, use or disclosure of MediaTek Software,
+* and information contained herein, in whole or in part, shall be strictly prohibited.
+*/
+/* MediaTek Inc. (C) 2016. All rights reserved.
+*
+* BY OPENING THIS FILE, RECEIVER HEREBY UNEQUIVOCALLY ACKNOWLEDGES AND AGREES
+* THAT THE SOFTWARE/FIRMWARE AND ITS DOCUMENTATIONS ("MEDIATEK SOFTWARE")
+* RECEIVED FROM MEDIATEK AND/OR ITS REPRESENTATIVES ARE PROVIDED TO RECEIVER ON
+* AN "AS-IS" BASIS ONLY. MEDIATEK EXPRESSLY DISCLAIMS ANY AND ALL WARRANTIES,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED WARRANTIES OF
+* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE OR NONINFRINGEMENT.
+* NEITHER DOES MEDIATEK PROVIDE ANY WARRANTY WHATSOEVER WITH RESPECT TO THE
+* SOFTWARE OF ANY THIRD PARTY WHICH MAY BE USED BY, INCORPORATED IN, OR
+* SUPPLIED WITH THE MEDIATEK SOFTWARE, AND RECEIVER AGREES TO LOOK ONLY TO SUCH
+* THIRD PARTY FOR ANY WARRANTY CLAIM RELATING THERETO. RECEIVER EXPRESSLY ACKNOWLEDGES
+* THAT IT IS RECEIVER'S SOLE RESPONSIBILITY TO OBTAIN FROM ANY THIRD PARTY ALL PROPER LICENSES
+* CONTAINED IN MEDIATEK SOFTWARE. MEDIATEK SHALL ALSO NOT BE RESPONSIBLE FOR ANY MEDIATEK
+* SOFTWARE RELEASES MADE TO RECEIVER'S SPECIFICATION OR TO CONFORM TO A PARTICULAR
+* STANDARD OR OPEN FORUM. RECEIVER'S SOLE AND EXCLUSIVE REMEDY AND MEDIATEK'S ENTIRE AND
+* CUMULATIVE LIABILITY WITH RESPECT TO THE MEDIATEK SOFTWARE RELEASED HEREUNDER WILL BE,
+* AT MEDIATEK'S OPTION, TO REVISE OR REPLACE THE MEDIATEK SOFTWARE AT ISSUE,
+* OR REFUND ANY SOFTWARE LICENSE FEES OR SERVICE CHARGE PAID BY RECEIVER TO
+* MEDIATEK FOR SUCH MEDIATEK SOFTWARE AT ISSUE.
+*/
+
+#include <malloc.h>
+#include <printf.h>
+#include <stdarg.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <string.h>
+#include <lib/zlib.h>
+
+#include <video.h>
+#include <part_interface.h>
+#include <platform/mt_typedefs.h>
+#include <dev/mrdump.h>
+#include <platform/mtk_key.h>
+#include <platform/mtk_wdt.h>
+#include <platform/mt_gpt.h>
+#include <target/board.h>
+#include <target/cust_key.h>
+#include <platform/boot_mode.h>
+#include <bootimg.h>
+#include <platform/ram_console.h>
+#include <arch/ops.h>
+#include <platform.h>
+#include <mt_boot.h>
+#include <platform/errno.h>
+#include "aee.h"
+#include "mrdump_private.h"
+
+#ifdef MTK_3LEVEL_PAGETABLE
+#include <target.h>
+#endif
+
+#define MRDUMP_DELAY_TIME 10
+
+extern BOOT_ARGUMENT *g_boot_arg;
+extern BOOTMODE g_boot_mode;
+
+static struct mrdump_control_block *mrdump_cb = NULL;
+
+static struct mrdump_cblock_result cblock_result;
+static unsigned int log_size;
+static int output_device;
+
+int mrdump_get_env(const char *name, char *out, int out_len)
+{
+	struct mrdump_expdb_config mrdump_config;
+	struct mrdump_dev *blkpart = mrdump_dev_blkpart(AEE_IPANIC_LABEL);
+
+	if (blkpart == NULL) {
+		dprintf(CRITICAL, "%s partition does not exist\n", AEE_IPANIC_LABEL);
+		return -ENODEV;
+	}
+
+	off_t part_total_size = partition_get_size_by_name(AEE_IPANIC_LABEL);
+	off_t offset;
+	bool  status;
+
+	offset = part_total_size - MRDUMP_CONFIG_EXPDB_OFFSET;
+	status = blkpart->read(blkpart, offset, (uint8_t *)&mrdump_config, sizeof(struct mrdump_expdb_config));
+	free(blkpart);
+	if (!status) {
+		dprintf(CRITICAL, "%s: bio_read fail\n", __func__);
+		return -EIO;
+	}
+
+	if (!strncmp(name, MRDUMP_OUTPUT, sizeof(MRDUMP_OUTPUT))) {
+		if (strlcpy(out, mrdump_config.output_dev, out_len) >= out_len) {
+			dprintf(CRITICAL, "%s: mrdump_config.output_dev too long\n", __func__);
+			return -1;
+		}
+		dprintf(CRITICAL, "%s: %s\n", MRDUMP_OUTPUT, out);
+	} else if (!strncmp(name, MRDUMP_ALLOCATE_SIZE, 20)) {
+		if (strlcpy(out, mrdump_config.allocate_size, out_len) >= out_len) {
+			dprintf(CRITICAL, "%s: mrdump_config.allocate_size too long\n", __func__);
+			return -1;
+		}
+		dprintf(CRITICAL, "%s: %s\n", MRDUMP_ALLOCATE_SIZE, out);
+	} else if (!strncmp(name, MRDUMP_MEM_SIZE, sizeof(MRDUMP_MEM_SIZE))) {
+		if (strlcpy(out, mrdump_config.mem_size, out_len) >= out_len) {
+			dprintf(CRITICAL, "%s: mrdump_config.mem_size too long\n", __func__);
+			return -1;
+		}
+	} else if (!strncmp(name, MRDUMP_LBAOOO, sizeof(MRDUMP_LBAOOO))) {
+		if (strlcpy(out, mrdump_config.lbaooo, out_len) >= out_len) {
+			dprintf(CRITICAL, "%s: mrdump_config.lbaooo too long\n", __func__);
+			return -1;
+		}
+	} else if (!strncmp(name, MRDUMP_DUMP_TYPE, sizeof(MRDUMP_DUMP_TYPE))) {
+		if (strlcpy(out, mrdump_config.dump_type, out_len) >= out_len) {
+			dprintf(CRITICAL, "%s: mrdump_config.dump_type too long\n", __func__);
+			return -1;
+		}
+	} else {
+		dprintf(CRITICAL, "unknown mrdump config %s\n", name);
+		return -1;
+	}
+	dprintf(CRITICAL, "%s: %s\n", name, out);
+	return 0;
+}
+
+int mrdump_set_env(const char *name, const char *value)
+{
+	struct mrdump_expdb_config mrdump_config;
+	off_t part_total_size;
+	off_t offset;
+	bool status;
+
+	memset(&mrdump_config, 0, sizeof(mrdump_config));
+	struct mrdump_dev *blkpart = mrdump_dev_blkpart(AEE_IPANIC_LABEL);
+
+	if (blkpart == NULL) {
+		dprintf(CRITICAL, "%s partition does not exist\n", AEE_IPANIC_LABEL);
+		return -ENODEV;
+	}
+
+	part_total_size = partition_get_size_by_name(AEE_IPANIC_LABEL);
+	offset = part_total_size - MRDUMP_CONFIG_EXPDB_OFFSET;
+	status =  blkpart->read(blkpart, offset, (uint8_t *)&mrdump_config, sizeof(struct mrdump_expdb_config));
+	if (!status) {
+		dprintf(CRITICAL, "%s: bio_read fail\n", __func__);
+		free(blkpart);
+		return -EIO;
+	}
+
+        if (mrdump_config.sig != MRDUMP_CONFIG_SIG) {
+            memset(&mrdump_config, 0, sizeof(struct mrdump_expdb_config));
+            mrdump_config.sig = MRDUMP_CONFIG_SIG;
+        }
+
+	if (!strncmp(name, MRDUMP_OUTPUT, sizeof(MRDUMP_OUTPUT))) {
+		memcpy(&mrdump_config.output_dev, value, sizeof(mrdump_config.output_dev));
+	} else if (!strncmp(name, MRDUMP_ALLOCATE_SIZE, sizeof(MRDUMP_ALLOCATE_SIZE))) {
+		memcpy(&mrdump_config.allocate_size, value, sizeof(mrdump_config.allocate_size));
+	} else if (!strncmp(name, MRDUMP_MEM_SIZE, sizeof(MRDUMP_MEM_SIZE))) {
+		memcpy(&mrdump_config.mem_size, value, sizeof(mrdump_config.mem_size));
+	} else if (!strncmp(name, MRDUMP_LBAOOO, sizeof(MRDUMP_LBAOOO))) {
+		memcpy(&mrdump_config.lbaooo, value, sizeof(mrdump_config.lbaooo));
+	} else if (!strncmp(name, MRDUMP_DUMP_TYPE, sizeof(MRDUMP_DUMP_TYPE))) {
+		memcpy(&mrdump_config.dump_type, value, sizeof(mrdump_config.dump_type));
+	} else {
+		dprintf(CRITICAL, "unknown mrdump config\n");
+		free(blkpart);
+		return -1;
+	}
+	dprintf(CRITICAL, "%s update to %s\n", name, value);
+
+	status =  blkpart->write(blkpart, offset, (uint8_t *)&mrdump_config, sizeof(struct mrdump_expdb_config));
+	if (!status) {
+		dprintf(CRITICAL, "%s: bio_write fail\n", __func__);
+		free(blkpart);
+		return -EIO;
+	}
+	free(blkpart);
+	return 0;
+}
+
+
+void voprintf(char type, const char *msg, va_list ap)
+{
+	char msgbuf[128], *p;
+
+	p = msgbuf;
+	if (msg[0] == '\r') {
+		*p++ = msg[0];
+		msg++;
+	}
+
+	*p++ = type;
+	*p++ = ':';
+	if (vsnprintf(p, sizeof(msgbuf) - (p - msgbuf), msg, ap) < 0) {
+		strlcpy(p, "<Message format error>\n", p  - msgbuf);
+	}
+
+	switch (type) {
+		case 'I':
+		case 'W':
+		case 'E':
+			video_printf("%s", msgbuf);
+			break;
+	}
+
+	dprintf(CRITICAL,"[%s] %s", MRDUMP_GO_DUMP, msgbuf);
+
+	/* Write log buffer */
+	p = msgbuf;
+	while ((*p != 0) && (log_size < sizeof(cblock_result.log_buf))) {
+		cblock_result.log_buf[log_size] = *p++;
+		log_size++;
+	}
+}
+
+void voprintf_verbose(const char *msg, ...)
+{
+	va_list ap;
+	va_start(ap, msg);
+	voprintf('V', msg, ap);
+	va_end(ap);
+}
+
+void voprintf_debug(const char *msg, ...)
+{
+	va_list ap;
+	va_start(ap, msg);
+	voprintf('D', msg, ap);
+	va_end(ap);
+}
+
+void voprintf_info(const char *msg, ...)
+{
+	va_list ap;
+	va_start(ap, msg);
+	voprintf('I', msg, ap);
+	va_end(ap);
+}
+
+void voprintf_warning(const char *msg, ...)
+{
+	va_list ap;
+	va_start(ap, msg);
+	voprintf('W', msg, ap);
+	va_end(ap);
+}
+
+void voprintf_error(const char *msg, ...)
+{
+	va_list ap;
+	va_start(ap, msg);
+	voprintf('E', msg, ap);
+	va_end(ap);
+}
+
+void vo_show_progress(int sizeM)
+{
+	video_set_cursor((video_get_rows() / 4) * 3, (video_get_colums() - 22)/ 2);
+	video_printf("=====================\n");
+	video_set_cursor((video_get_rows() / 4) * 3 + 1, (video_get_colums() - 22)/ 2);
+	video_printf(">>> Written %4dM <<<\n", sizeM);
+	video_set_cursor((video_get_rows() / 4) * 3 + 2, (video_get_colums() - 22)/ 2);
+	video_printf("=====================\n");
+	video_set_cursor(video_get_rows() - 1, 0);
+
+	dprintf(CRITICAL,"... Written %dM\n", sizeM);
+}
+
+static void mrdump_status(const char *status, const char *fmt, va_list ap)
+{
+	char *dest = cblock_result.status;
+	dest += strlcpy(dest, status, sizeof(cblock_result.status));
+	*dest++ = '\n';
+
+	vsnprintf(dest, sizeof(cblock_result.status) - (dest - cblock_result.status), fmt, ap);
+}
+
+void mrdump_status_ok(const char *fmt, ...)
+{
+	va_list ap;
+	va_start(ap, fmt);
+	mrdump_status("OK", fmt, ap);
+	va_end(ap);
+}
+
+void mrdump_status_none(const char *fmt, ...)
+{
+	va_list ap;
+	va_start(ap, fmt);
+	mrdump_status("NONE", fmt, ap);
+	va_end(ap);
+}
+
+void mrdump_status_error(const char *fmt, ...)
+{
+	va_list ap;
+	va_start(ap, fmt);
+	mrdump_status("FAILED", fmt, ap);
+	va_end(ap);
+}
+
+const const char *mrdump_mode2string(uint8_t mode)
+{
+	switch (mode) {
+		case AEE_REBOOT_MODE_NORMAL:
+			return "NORMAL-BOOT";
+
+		case AEE_REBOOT_MODE_KERNEL_OOPS:
+			return "KERNEL-OOPS";
+
+		case AEE_REBOOT_MODE_KERNEL_PANIC:
+			return "KERNEL-PANIC";
+
+		case AEE_REBOOT_MODE_NESTED_EXCEPTION:
+			return "NESTED-CPU-EXCEPTION";
+
+		case AEE_REBOOT_MODE_WDT:
+			return "HWT";
+
+		case AEE_REBOOT_MODE_EXCEPTION_KDUMP:
+			return "MANUALDUMP";
+
+		case AEE_REBOOT_MODE_MRDUMP_KEY:
+			return "MRDUMP_KEY";
+
+		case AEE_REBOOT_MODE_HANG_DETECT:
+			return "KERNEL-HANG-DETECT";
+
+		default:
+			return "UNKNOWN-BOOT";
+	}
+}
+
+#define MRDUMP_EXPDB_OFFSET 3145728
+
+static void mrdump_write_result(void)
+{
+	struct mrdump_dev *blkpart = mrdump_dev_blkpart("expdb");
+	if (blkpart != NULL) {
+		u64 part_size = blkpart->get_size(blkpart);
+		if (part_size < MRDUMP_EXPDB_OFFSET + sizeof(cblock_result)) {
+			dprintf(CRITICAL, "%s: partition size(%llx) is less then reserved (%x)\n",
+				__func__, part_size, MRDUMP_EXPDB_OFFSET);
+			free(blkpart);
+			return;
+		}
+		blkpart->write(blkpart, part_size - MRDUMP_EXPDB_OFFSET,
+			       (uint8_t *) &cblock_result, sizeof(cblock_result));
+		free(blkpart);
+	}
+	else {
+		dprintf(CRITICAL, "%s: Cannot find expdb partition\n", __func__);
+	}
+}
+
+#define SIZE_1MB 1048576ULL
+#define SIZE_64MB 67108864ULL
+
+static uint64_t mrdump_mem_size(void)
+{
+	uint64_t total_dump_size = physical_memory_size();
+	char mem_size_param[8] = {0};
+
+	if (mrdump_get_env("mrdump_mem_size", mem_size_param, sizeof(mem_size_param)))
+		dprintf(CRITICAL, "%s: mrdump_get_env fail\n", __func__);
+
+	if (strcmp(mem_size_param, "")) {
+		uint64_t mem_size = atoi(mem_size_param) * SIZE_1MB;
+		voprintf_info("Memory dump size set to %uM\n", (unsigned int) (mem_size / SIZE_1MB));
+		if (mem_size >= SIZE_64MB) {
+			/* minimum 64m */
+			total_dump_size = MIN(total_dump_size, mem_size);
+		}
+	}
+	return total_dump_size;
+}
+
+int mrdump_set_output_device(const char *output_dev)
+{
+	int retval = MRDUMP_DEV_UNKNOWN;
+	if (strcmp(output_dev, "none") == 0) {
+		retval = MRDUMP_DEV_NONE;
+	}
+	else if (strcmp(output_dev, "null") == 0) {
+		retval = MRDUMP_DEV_NULL;
+	}
+	else if (strcmp(output_dev, "usb") == 0) {
+		retval = MRDUMP_DEV_USB;
+	}
+	else if (strcmp(output_dev, "partition") == 0) {
+		retval = MRDUMP_DEV_PARTITION;
+	}
+	else if (strcmp(output_dev, "internal-storage") == 0) {
+		retval = MRDUMP_DEV_ISTORAGE;
+	}
+	if (retval != MRDUMP_DEV_UNKNOWN) {
+		if (mrdump_set_env("mrdump_output", (char *)output_dev) == 0) {
+			dprintf(CRITICAL, "%s: defaults: %s\n",__func__, output_dev);
+		}
+		else {
+			dprintf(CRITICAL, "%s: fail to set default mrdump output device\n", __func__);
+		}
+	}
+	else {
+		dprintf(CRITICAL, "%s: unknown output device %s\n",__func__, output_dev);
+	}
+	return retval;
+}
+
+int mrdump_get_default_output_device(void)
+{
+	char output_device_param[64] = "";
+
+	if (mrdump_get_env("mrdump_output", output_device_param, sizeof(output_device_param)))
+		dprintf(CRITICAL, "%s: mrdump_get_env fail\n", __func__);
+
+	if (strcmp(output_device_param, "")) {
+		if (strcmp(output_device_param, "none") == 0)
+			return MRDUMP_DEV_NONE;
+		if (strcmp(output_device_param, "null") == 0)
+			return MRDUMP_DEV_NULL;
+		if (strcmp(output_device_param, "internal-storage") == 0)
+			return MRDUMP_DEV_ISTORAGE;
+		if (strcmp(output_device_param, "usb") == 0)
+			return MRDUMP_DEV_USB;
+		if (strcmp(output_device_param, "partition") == 0)
+			return MRDUMP_DEV_PARTITION;
+		dprintf(CRITICAL, "%s: unknown output device %s\n",__func__,
+			output_device_param);
+		return MRDUMP_DEV_UNKNOWN;
+	}
+#if defined(MRDUMP_DEFAULT_NONE)
+	return mrdump_set_output_device("none");
+#elif defined(MRDUMP_DEFAULT_NULL)
+	return mrdump_set_output_device("null");
+#elif defined(MRDUMP_DEFAULT_USB_DUMP)
+	return mrdump_set_output_device("usb");
+#elif defined(MRDUMP_DEFAULT_MRDUMP_PARTITION)
+	return mrdump_set_output_device("partition");
+#elif defined(MRDUMP_DEFAULT_DATA_PARTITION)
+	return mrdump_set_output_device("internal-storage");
+#else
+#ifdef MRDUMP_PARTITION_ENABLE
+	return mrdump_set_output_device("partition");
+#else
+	return mrdump_set_output_device("internal-storage");
+#endif
+#endif
+}
+
+static struct kzip_addlist *mrdump_memlist_fill(struct mrdump_control_block *mrdump_cblock)
+{
+	struct kzip_addlist *memlist = malloc(sizeof(struct kzip_addlist) * 4);
+	if (memlist == NULL) {
+		return NULL;
+	}
+	void *bufp = malloc(MRDUMP_CORE_HEADER_SIZE);
+	if (bufp == NULL) {
+		free(memlist);
+		return NULL;
+	}
+	memset(bufp, 0, MRDUMP_CORE_HEADER_SIZE);
+
+	memlist[0].address = (uint64_t)(uintptr_t) bufp;
+	memlist[0].size = MRDUMP_CORE_HEADER_SIZE;
+	memlist[0].type = MEM_NO_MAP;
+	memlist[0].memmap = 0;
+	memlist[0].pageflags = 0;
+	memlist[0].struct_page_size = 0;
+	memlist[1].address = (uint64_t)(uintptr_t) mrdump_cb_addr();
+	memlist[1].size = mrdump_cb_size();
+	memlist[1].type = MEM_NO_MAP;
+	memlist[1].memmap = 0;
+	memlist[1].pageflags = 0;
+	memlist[1].struct_page_size = 0;
+	memlist[2].address = DRAM_PHY_ADDR;
+	memlist[2].size = mrdump_mem_size();
+	memlist[2].type = MEM_DO_MAP;
+	memlist[2].memmap = mrdump_cblock->machdesc.memmap;
+	memlist[2].pageflags = mrdump_cblock->machdesc.pageflags;
+	memlist[2].struct_page_size = mrdump_cblock->machdesc.struct_page_size;
+	memlist[3].address = 0;
+	memlist[3].size = 0;
+	memlist[3].type = MEM_NO_MAP;
+	memlist[3].memmap = 0;
+	memlist[3].pageflags = 0;
+	memlist[3].struct_page_size = 0;
+	return memlist;
+}
+
+static void mrdump_memlist_free(struct kzip_addlist *memlist)
+{
+	free((void *)(uintptr_t)memlist[0].address);
+	free(memlist);
+}
+
+static void kdump_ui(struct mrdump_control_block *mrdump_cblock)
+{
+	video_clear_image_by_color(0xFFFF7F00, 0, 0, CFG_DISPLAY_WIDTH, CFG_DISPLAY_HEIGHT);
+	video_set_bgcolor(0xFFFF7F00);
+	video_set_fgcolor(0xFFFF0000);
+	video_set_cursor(0, 0);
+
+	mrdump_status_error("Unknown error\n");
+	voprintf_info("Kdump triggerd by '%s' (address:%x, size:%lluM)\n",
+		      mrdump_mode2string(mrdump_cblock->crash_record.reboot_mode),
+		      DRAM_PHY_ADDR, mrdump_mem_size() / 0x100000UL);
+
+	/* check machdesc crc */
+	uint32_t mcrc = crc32(0xffffffff, (const unsigned char*)&mrdump_cblock->machdesc,
+			      sizeof(struct mrdump_machdesc)) ^ 0xffffffff;
+	if (mcrc != mrdump_cblock->machdesc_crc) {
+		voprintf_error("Control block machdesc field CRC error (%08x, %08x).\n",
+			       mcrc, mrdump_cblock->machdesc_crc);
+		return;
+	}
+
+	struct kzip_addlist *memlist_cmm = mrdump_memlist_fill_cmm(mrdump_cblock);
+	struct kzip_addlist *memlist = mrdump_memlist_fill(mrdump_cblock);
+	if (memlist == NULL) {
+		voprintf_error("Cannot allcate memlist memory.\n");
+		return;
+	}
+	mrdump_core_header_init(mrdump_cblock, memlist);
+
+	struct aee_timer elapse_time;
+	aee_timer_init(&elapse_time);
+	aee_timer_start(&elapse_time);
+	int dump_ok;
+	switch (output_device) {
+		case  MRDUMP_DEV_NONE:
+			mrdump_status_none("Output to None (disabled)\n");
+			voprintf_info("Output to None (disabled)\n");
+			dump_ok = 0;
+			break;
+		case MRDUMP_DEV_NULL:
+			dump_ok = mrdump_null_output(mrdump_cblock, memlist, memlist_cmm);
+			break;
+		case MRDUMP_DEV_ISTORAGE:
+			dump_ok = mrdump_ext4_output(mrdump_cblock, memlist, memlist_cmm, mrdump_dev_blkpart("userdata"));
+			break;
+		case MRDUMP_DEV_USB:
+			dump_ok = mrdump_usb_output(mrdump_cblock, memlist, memlist_cmm);
+			break;
+		case MRDUMP_DEV_PARTITION:
+			dump_ok = mrdump_partition_output(mrdump_cblock, memlist, memlist_cmm, mrdump_dev_blkpart("mrdump"));
+			break;
+		default:
+			voprintf_error("Unsupport device id %d\n", output_device);
+			dump_ok = -1;
+	}
+	mrdump_memlist_free(memlist);
+	mrdump_memlist_free_cmm(memlist_cmm);
+
+	aee_mrdump_flush_cblock(mrdump_cblock);
+	aee_timer_stop(&elapse_time);
+	voprintf_info("Dump finished.(%s, %d sec)\n", dump_ok == 0 ? "ok" : "failed", elapse_time.acc_ms / 1000);
+
+	mtk_wdt_restart();
+
+	video_clean_screen();
+	video_set_cursor(0, 0);
+}
+
+int mrdump_detection(void)
+{
+	if (mrdump_check_enable() > MRDUMP_ALWAYS_ENABLE)
+		return 0;
+
+	mrdump_key_secure_enable();
+	output_device = mrdump_get_default_output_device();
+	if (output_device == MRDUMP_DEV_UNKNOWN) {
+		return 0;
+	}
+	if (!ram_console_is_abnormal_boot()) {
+		dprintf(CRITICAL, "MT-RAMDUMP: No exception detected, skipped\n");
+		return 0;
+	}
+
+	mrdump_cb = aee_mrdump_get_params();
+	if (mrdump_cb == NULL) {
+		dprintf(CRITICAL, "MT-RAMDUMP control block not found\n");
+		return 0;
+	}
+
+	memset(&cblock_result, 0, sizeof(struct mrdump_cblock_result));
+	log_size = 0;
+	strlcpy(cblock_result.sig, MRDUMP_GO_DUMP, sizeof(cblock_result.sig));
+
+	uint8_t reboot_mode = mrdump_cb->crash_record.reboot_mode;
+
+	if (!g_boot_arg->ddr_reserve_enable) {
+		voprintf_debug("DDR reserve mode disabled\n");
+		mrdump_status_none("DDR reserve mode disabled\n");
+		goto error;
+	}
+
+	if (!g_boot_arg->ddr_reserve_success) {
+		voprintf_debug("DDR reserve mode failed\n");
+		mrdump_status_none("DDR reserve mode failed\n");
+		goto error;
+	}
+
+	if (mrdump_cb->enabled != MRDUMP_ENABLE_COOKIE) {
+		voprintf_debug("Runtime disabled %x\n", mrdump_cb->enabled);
+		mrdump_status_none("Runtime disabled\n");
+		goto error;
+	}
+
+	voprintf_debug("sram record with mode %d\n", reboot_mode);
+	switch (reboot_mode) {
+		case AEE_REBOOT_MODE_GZ_WDT:
+		case AEE_REBOOT_MODE_WDT: {
+			goto end;
+		}
+		case AEE_REBOOT_MODE_NORMAL: {
+			/* MRDUMP_KEY reboot*/
+			if (ram_console_reboot_by_mrdump_key && ram_console_reboot_by_mrdump_key()) {
+				mrdump_cb->crash_record.reboot_mode = AEE_REBOOT_MODE_MRDUMP_KEY;
+				mrdump_status_none("set reboot_mode to MRDUMP_KEY\n");
+				goto end;
+			} else
+				return 0;
+		}
+		case AEE_REBOOT_MODE_KERNEL_OOPS:
+		case AEE_REBOOT_MODE_KERNEL_PANIC:
+		case AEE_REBOOT_MODE_NESTED_EXCEPTION:
+		case AEE_REBOOT_MODE_EXCEPTION_KDUMP:
+		case AEE_REBOOT_MODE_MRDUMP_KEY:
+		case AEE_REBOOT_MODE_GZ_KE:
+		case AEE_REBOOT_MODE_HANG_DETECT:
+			goto end;
+	}
+	voprintf_debug("Unsupport exception type\n");
+	mrdump_status_none("Unsupport exception type\n");
+
+error:
+	mrdump_write_result();
+	return 0;
+end:
+	if (output_device == MRDUMP_DEV_USB) {
+		g_boot_mode = FASTBOOT;
+		if (mrdump_set_env("mrdump_output", "usb")) {
+			dprintf(CRITICAL, "%s: default usb dump\n",__func__);
+		}
+		else {
+			dprintf(CRITICAL, "%s: fail to set default usb mrdump\n", __func__);
+		}
+	}
+
+	return 1;
+}
+
+void mrdump_reboot(void)
+{
+#ifdef MTK_PMIC_FULL_RESET
+	voprintf_debug("Ready for full pmic reset\n");
+	mrdump_write_result();
+	mtk_arch_full_reset();
+#else
+	voprintf_debug("Ready for reset\n");
+	mrdump_write_result();
+	mtk_arch_reset(1);
+#endif
+}
+
+int mrdump_run2(void)
+{
+	if (mrdump_cb != NULL) {
+		kdump_ui(mrdump_cb);
+		if (output_device != MRDUMP_DEV_USB) {
+			mrdump_reboot();
+		}
+		mrdump_write_result();
+		return 1;
+	}
+	return 0;
+}
+
+void aee_timer_init(struct aee_timer *t)
+{
+	memset(t, 0, sizeof(struct aee_timer));
+}
+
+void aee_timer_start(struct aee_timer *t)
+{
+	t->start_ms = get_timer_masked();
+}
+
+void aee_timer_stop(struct aee_timer *t)
+{
+	t->acc_ms += (get_timer_masked() - t->start_ms);
+	t->start_ms = 0;
+}
+
+#ifdef MTK_3LEVEL_PAGETABLE
+vaddr_t scratch_addr(void)
+{
+	return (vaddr_t)target_get_scratch_address();
+}
+#endif
+

+ 163 - 0
app/mt_boot/aee/aee.h

@@ -0,0 +1,163 @@
+/* Copyright Statement:
+*
+* This software/firmware and related documentation ("MediaTek Software") are
+* protected under relevant copyright laws. The information contained herein
+* is confidential and proprietary to MediaTek Inc. and/or its licensors.
+* Without the prior written permission of MediaTek inc. and/or its licensors,
+* any reproduction, modification, use or disclosure of MediaTek Software,
+* and information contained herein, in whole or in part, shall be strictly prohibited.
+*/
+/* MediaTek Inc. (C) 2016. All rights reserved.
+*
+* BY OPENING THIS FILE, RECEIVER HEREBY UNEQUIVOCALLY ACKNOWLEDGES AND AGREES
+* THAT THE SOFTWARE/FIRMWARE AND ITS DOCUMENTATIONS ("MEDIATEK SOFTWARE")
+* RECEIVED FROM MEDIATEK AND/OR ITS REPRESENTATIVES ARE PROVIDED TO RECEIVER ON
+* AN "AS-IS" BASIS ONLY. MEDIATEK EXPRESSLY DISCLAIMS ANY AND ALL WARRANTIES,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED WARRANTIES OF
+* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE OR NONINFRINGEMENT.
+* NEITHER DOES MEDIATEK PROVIDE ANY WARRANTY WHATSOEVER WITH RESPECT TO THE
+* SOFTWARE OF ANY THIRD PARTY WHICH MAY BE USED BY, INCORPORATED IN, OR
+* SUPPLIED WITH THE MEDIATEK SOFTWARE, AND RECEIVER AGREES TO LOOK ONLY TO SUCH
+* THIRD PARTY FOR ANY WARRANTY CLAIM RELATING THERETO. RECEIVER EXPRESSLY ACKNOWLEDGES
+* THAT IT IS RECEIVER'S SOLE RESPONSIBILITY TO OBTAIN FROM ANY THIRD PARTY ALL PROPER LICENSES
+* CONTAINED IN MEDIATEK SOFTWARE. MEDIATEK SHALL ALSO NOT BE RESPONSIBLE FOR ANY MEDIATEK
+* SOFTWARE RELEASES MADE TO RECEIVER'S SPECIFICATION OR TO CONFORM TO A PARTICULAR
+* STANDARD OR OPEN FORUM. RECEIVER'S SOLE AND EXCLUSIVE REMEDY AND MEDIATEK'S ENTIRE AND
+* CUMULATIVE LIABILITY WITH RESPECT TO THE MEDIATEK SOFTWARE RELEASED HEREUNDER WILL BE,
+* AT MEDIATEK'S OPTION, TO REVISE OR REPLACE THE MEDIATEK SOFTWARE AT ISSUE,
+* OR REFUND ANY SOFTWARE LICENSE FEES OR SERVICE CHARGE PAID BY RECEIVER TO
+* MEDIATEK FOR SUCH MEDIATEK SOFTWARE AT ISSUE.
+*/
+
+#if !defined (__AEE_H__)
+#define __AEE_H__
+
+#include <stdint.h>
+#include <sys/types.h>
+#include <dev/mrdump.h>
+#include <stdarg.h>
+#include "KEHeader.h"
+
+typedef enum {
+	AEE_MODE_MTK_ENG = 1,
+	AEE_MODE_MTK_USER,
+	AEE_MODE_CUSTOMER_ENG,
+	AEE_MODE_CUSTOMER_USER
+} AEE_MODE;
+
+typedef enum {
+	AEE_REBOOT_MODE_NORMAL = 0,
+	AEE_REBOOT_MODE_KERNEL_OOPS,
+	AEE_REBOOT_MODE_KERNEL_PANIC,
+	AEE_REBOOT_MODE_NESTED_EXCEPTION,
+	AEE_REBOOT_MODE_WDT,
+	AEE_REBOOT_MODE_EXCEPTION_KDUMP,
+	AEE_REBOOT_MODE_MRDUMP_KEY,
+	AEE_REBOOT_MODE_GZ_KE,
+	AEE_REBOOT_MODE_GZ_WDT,
+	AEE_REBOOT_MODE_HANG_DETECT,
+} AEE_REBOOT_MODE;
+
+/*#define AEE_IPANIC_MAGIC 0xaee0dead
+#define AEE_IPANIC_PHDR_VERSION   0x04
+
+struct ipanic_header {
+	// The magic/version field cannot be moved or resize //
+	uint32_t magic;
+	uint32_t version;
+
+	uint32_t oops_header_offset;
+	uint32_t oops_header_length;
+
+	uint32_t oops_detail_offset;
+	uint32_t oops_detail_length;
+
+	uint32_t console_offset;
+	uint32_t console_length;
+
+	uint32_t android_main_offset;
+	uint32_t android_main_length;
+
+	uint32_t android_event_offset;
+	uint32_t android_event_length;
+
+	uint32_t android_radio_offset;
+	uint32_t android_radio_length;
+
+	uint32_t android_system_offset;
+	uint32_t android_system_length;
+
+	uint32_t userspace_info_offset;
+	uint32_t userspace_info_length;
+};*/
+
+#define IPANIC_OOPS_HEADER_PROCESS_NAME_LENGTH 256
+#define IPANIC_OOPS_HEADER_BACKTRACE_LENGTH 3840
+
+struct ipanic_oops_header {
+	char process_path[IPANIC_OOPS_HEADER_PROCESS_NAME_LENGTH];
+	char backtrace[IPANIC_OOPS_HEADER_BACKTRACE_LENGTH];
+};
+
+const char *mrdump_mode2string(uint8_t mode);
+
+struct mrdump_control_block *aee_mrdump_get_params(void);
+struct mrdump_control_block *mrdump_cb_addr(void);
+int mrdump_cb_size(void);
+
+void aee_mrdump_flush_cblock(struct mrdump_control_block *bufp);
+
+void voprintf(char type, const char *msg, va_list ap);
+void voprintf_verbose(const char *msg, ...);
+void voprintf_debug(const char *msg, ...);
+void voprintf_info(const char *msg, ...);
+void voprintf_warning(const char *msg, ...);
+void voprintf_error(const char *msg, ...);
+void vo_show_progress(int sizeM);
+
+void mrdump_status_none(const char *fmt, ...);
+void mrdump_status_ok(const char *fmt, ...);
+void mrdump_status_error(const char *fmt, ...);
+
+#define AEE_IPANIC_LABEL "expdb"
+#define MRDUMP_CONFIG_EXPDB_OFFSET 2101248 //2MB+4KB
+
+#define MRDUMP_ALLOCATE_SIZE "mrdump_allocate_size"
+#define MRDUMP_MEM_SIZE "mrdump_mem_size"
+#define MRDUMP_OUTPUT "mrdump_output"
+#define MRDUMP_LBAOOO "mrdump_lbaooo"
+#define MRDUMP_DUMP_TYPE "mrdump_dump_type"
+#define MRDUMP_CONFIG_SIG 0x3043524d
+
+struct __attribute__((__packed__)) mrdump_expdb_config {
+    uint32_t sig;
+    uint32_t size;
+
+    char output_dev[64];
+    char mem_size[16];
+    char allocate_size[16];
+    char lbaooo[24];
+    char dump_type[32];
+};
+
+int mrdump_set_env(const char *name, const char *value);
+int mrdump_get_env(const char *name, char *out, int out_len);
+
+struct aee_timer {
+	unsigned int acc_ms;
+
+	unsigned int start_ms;
+};
+
+void aee_timer_init(struct aee_timer *t);
+void aee_timer_start(struct aee_timer *t);
+void aee_timer_stop(struct aee_timer *t);
+
+/* FIXME: move to platform/mtk_wdt.h */
+extern void mtk_wdt_restart(void);
+extern ulong get_timer_masked (void);
+bool ram_console_reboot_by_mrdump_key(void)__attribute__((weak));
+
+extern bool cmdline_append(const char* append_string);
+
+#endif

+ 246 - 0
app/mt_boot/aee/armmmu_translate.c

@@ -0,0 +1,246 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include "KEHeader.h"
+
+extern uint64_t get_mpt(void);
+extern uint64_t kedump_mem_read(uint64_t data, unsigned long sz, void *buf);
+#if 0
+extern int sLOG(char *fmt, ...);
+#define LOG(fmt, ...)           \
+    do { \
+        sLOG(fmt, ##__VA_ARGS__);       \
+        printf(fmt, ##__VA_ARGS__); \
+    } while(0)
+
+#else
+#define LOG(fmt, ...)
+#endif
+static int read_mem(uint64_t paddr, void *buf, unsigned long size)
+{
+	uint64_t ret = 0;
+
+	ret = kedump_mem_read(paddr, size, buf);
+	return (ret == size) ? 0 : -1;
+}
+
+
+#define PAGE_SIZE 4096
+#define PNUM_64 (PAGE_SIZE / sizeof(uint64_t))
+static uint64_t lxpage[PNUM_64];
+
+/* ARM PGD/PMD first 3 pages for userspace, last 1 pages for kernel space */
+#define PNUM_32 (PAGE_SIZE * 4 / sizeof(uint32_t))
+static uint32_t l1page32[PNUM_32];
+
+/* ARM L2 PTE 512 entry and each entry 4 bytes */
+#define PNUM_L2_32 512
+static uint32_t l2page32[PNUM_L2_32];
+
+static uint64_t mmutable_64_translate_l3(uint64_t vptr,
+		uint64_t ptable)
+{
+	int ret = 0;
+	uint64_t pa;
+
+	unsigned int lxidx = (vptr >> 12) & 0x1ff;
+	if (lxidx >= PNUM_64) {
+		LOG("address:0x%llx index:%d overflow error\n", vptr, lxidx);
+		return 0;
+	}
+
+	memset(lxpage, 0, PAGE_SIZE);
+	ret = read_mem(ptable, lxpage, PAGE_SIZE);
+	if (ret == 0) {
+		LOG("(%d)ent value:0x%llx\n", lxidx, lxpage[lxidx]);
+	} else {
+		return 0;
+	}
+
+	switch(lxpage[lxidx] & 3) {
+		case 3:
+			pa = (lxpage[lxidx] & 0x0000fffffffff000)
+				+ (vptr & 0xfff);
+			break;
+		default:
+			LOG("invalid (%d)ent value:0x%llx\n", lxidx,
+					lxpage[lxidx]);
+			pa = 0;
+	}
+
+	return pa;
+}
+
+static uint64_t mmutable_64_translate_l2(uint64_t vptr,
+		uint64_t ptable)
+{
+	int ret = 0;
+	uint64_t pa;
+	uint64_t next_table_address;
+
+	unsigned int lxidx = (vptr >> 21) & 0x1ff;
+	if (lxidx >= PNUM_64) {
+		LOG("address:0x%llx index:%d overflow error\n", vptr, lxidx);
+		return 0;
+	}
+
+	memset(lxpage, 0, PAGE_SIZE);
+	ret = read_mem(ptable, lxpage, PAGE_SIZE);
+	if (ret == 0) {
+		LOG("(%d)ent value:0x%llx\n", lxidx, lxpage[lxidx]);
+	} else {
+		return 0;
+	}
+
+	switch(lxpage[lxidx] & 3) {
+		case 1:
+			pa = (lxpage[lxidx] & 0x0000ffffffe00000)
+				+ (vptr & 0x1fffff);
+			break;
+		case 3:
+			next_table_address = lxpage[lxidx]
+				& 0x0000fffffffff000;
+			pa = mmutable_64_translate_l3(vptr,
+					next_table_address);
+			break;
+		default:
+			LOG("invalid (%d)ent value:0x%llx\n", lxidx,
+					lxpage[lxidx]);
+			pa = 0;
+	}
+
+	return pa;
+}
+
+static uint64_t mmutable_64_translate_l1(uint64_t vptr,
+		uint64_t ptable)
+{
+	int ret = 0;
+	uint64_t pa;
+	uint64_t next_table_address;
+
+	unsigned int lxidx = (vptr >> 30) & 0x1ff;
+	if (lxidx >= PNUM_64) {
+		LOG("address:0x%llx index:%d overflow error\n", vptr, lxidx);
+		return 0;
+	}
+
+	memset(lxpage, 0, PAGE_SIZE);
+	ret = read_mem(ptable, lxpage, PAGE_SIZE);
+	if (ret == 0) {
+		LOG("(%d)ent value:0x%llx\n", lxidx, lxpage[lxidx]);
+	} else {
+		return 0;
+	}
+
+	switch(lxpage[lxidx] & 3) {
+		case 1:
+			pa = (lxpage[lxidx] & 0x0000ffffc0000000)
+				+ (vptr & 0x3fffffff);
+			break;
+		case 3:
+			next_table_address = lxpage[lxidx]
+				& 0x0000fffffffff000;
+			pa = mmutable_64_translate_l2(vptr,
+					next_table_address);
+			break;
+		default:
+			LOG("invalid (%d)ent value:0x%llx\n", lxidx,
+					lxpage[lxidx]);
+			pa = 0;
+	}
+
+	return pa;
+}
+
+uint64_t v2p_64(uint64_t vptr)
+{
+	uint64_t mpt = get_mpt();
+	/* LOG("mater_page_table:0x%llx, vptr:0x%llx\n", mpt, vptr); */
+
+	if ((vptr & 0x8000000000000000) != 0) {
+		return mmutable_64_translate_l1(vptr, mpt);
+	} else {
+		LOG("illegal address:0x%llx\n", vptr);
+	}
+
+	return 0;
+}
+
+static uint64_t mmutable_32_translate_l2(uint64_t vptr, uint64_t ptable)
+{
+	int ret;
+	uint64_t pa = 0;
+
+	unsigned int lxidx = (vptr >> 12) & 0x1ff;
+
+	memset(l2page32, 0, sizeof(l2page32));
+	ret = read_mem(ptable, l2page32, sizeof(l2page32));
+	if (ret == 0) {
+		LOG("(%d)ent value:0x%x\n", lxidx, l2page32[lxidx]);
+	} else {
+		LOG("invalid l2 page table:0x%llx\n", ptable);
+		return 0;
+	}
+
+	if (l2page32[lxidx] & 1)
+		pa = (l2page32[lxidx] & 0xfffff000) + (vptr & 0xfff);
+	else
+		LOG("invalid (%d)ent value:0x%x\n", lxidx, l2page32[lxidx]);
+
+	return pa;
+}
+
+static uint64_t mmutable_32_translate_l1(uint64_t vptr, uint64_t ptable)
+{
+	int ret;
+	uint64_t pa;
+	uint64_t next_table_address;
+
+	unsigned int lxidx = (vptr >> 20) & 0xfff;
+	if (lxidx >= PNUM_32) {
+		LOG("address:0x%llx index:%d overflow error\n", vptr, lxidx);
+		return 0;
+	}
+
+	memset(l1page32, 0, sizeof(l1page32));
+	ret = read_mem(ptable, l1page32, sizeof(l1page32));
+	if (ret == 0) {
+		LOG("(%d)ent value:0x%x\n", lxidx, l1page32[lxidx]);
+	} else {
+		LOG("invalid l1 page table:0x%llx\n", ptable);
+		return 0;
+	}
+
+	switch(l1page32[lxidx] & 3) {
+	case 1:
+		/* PMD point address is 1KB allign */
+		next_table_address = l1page32[lxidx] & 0xfffff000;
+		pa = mmutable_32_translate_l2(vptr, next_table_address);
+		break;
+	case 2:
+		/* [31:20]12bit as PMD index */
+		pa = (l1page32[lxidx] & 0xfff00000) + (vptr & 0xfffff);
+		break;
+	default:
+		LOG("invalid (%d)ent value:0x%x\n", lxidx, l1page32[lxidx]);
+		pa = 0;
+	}
+
+	return pa;
+}
+
+
+uint64_t v2p_32(uint64_t vptr)
+{
+	uint64_t mpt = get_mpt();
+
+	if (vptr > 0xbf000000) {
+		return mmutable_32_translate_l1(vptr, mpt);
+	} else {
+		LOG("illegal address:0x%llx\n", vptr);
+	}
+
+	return 0;
+}
+

+ 419 - 0
app/mt_boot/aee/mrdump_datafs.c

@@ -0,0 +1,419 @@
+/* Copyright Statement:
+*
+* This software/firmware and related documentation ("MediaTek Software") are
+* protected under relevant copyright laws. The information contained herein
+* is confidential and proprietary to MediaTek Inc. and/or its licensors.
+* Without the prior written permission of MediaTek inc. and/or its licensors,
+* any reproduction, modification, use or disclosure of MediaTek Software,
+* and information contained herein, in whole or in part, shall be strictly prohibited.
+*/
+/* MediaTek Inc. (C) 2016. All rights reserved.
+*
+* BY OPENING THIS FILE, RECEIVER HEREBY UNEQUIVOCALLY ACKNOWLEDGES AND AGREES
+* THAT THE SOFTWARE/FIRMWARE AND ITS DOCUMENTATIONS ("MEDIATEK SOFTWARE")
+* RECEIVED FROM MEDIATEK AND/OR ITS REPRESENTATIVES ARE PROVIDED TO RECEIVER ON
+* AN "AS-IS" BASIS ONLY. MEDIATEK EXPRESSLY DISCLAIMS ANY AND ALL WARRANTIES,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED WARRANTIES OF
+* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE OR NONINFRINGEMENT.
+* NEITHER DOES MEDIATEK PROVIDE ANY WARRANTY WHATSOEVER WITH RESPECT TO THE
+* SOFTWARE OF ANY THIRD PARTY WHICH MAY BE USED BY, INCORPORATED IN, OR
+* SUPPLIED WITH THE MEDIATEK SOFTWARE, AND RECEIVER AGREES TO LOOK ONLY TO SUCH
+* THIRD PARTY FOR ANY WARRANTY CLAIM RELATING THERETO. RECEIVER EXPRESSLY ACKNOWLEDGES
+* THAT IT IS RECEIVER'S SOLE RESPONSIBILITY TO OBTAIN FROM ANY THIRD PARTY ALL PROPER LICENSES
+* CONTAINED IN MEDIATEK SOFTWARE. MEDIATEK SHALL ALSO NOT BE RESPONSIBLE FOR ANY MEDIATEK
+* SOFTWARE RELEASES MADE TO RECEIVER'S SPECIFICATION OR TO CONFORM TO A PARTICULAR
+* STANDARD OR OPEN FORUM. RECEIVER'S SOLE AND EXCLUSIVE REMEDY AND MEDIATEK'S ENTIRE AND
+* CUMULATIVE LIABILITY WITH RESPECT TO THE MEDIATEK SOFTWARE RELEASED HEREUNDER WILL BE,
+* AT MEDIATEK'S OPTION, TO REVISE OR REPLACE THE MEDIATEK SOFTWARE AT ISSUE,
+* OR REFUND ANY SOFTWARE LICENSE FEES OR SERVICE CHARGE PAID BY RECEIVER TO
+* MEDIATEK FOR SUCH MEDIATEK SOFTWARE AT ISSUE.
+*/
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <malloc.h>
+#include <stdint.h>
+#include <string.h>
+#include <platform/mt_typedefs.h>
+#include <platform/mtk_wdt.h>
+#include <lib/zlib.h>
+
+#include "aee.h"
+#include "mrdump_private.h"
+
+#define BLKSIZE         4096
+#define MAX_CONTINUE    16                      // only 1MB memory for lk
+#define EXSPACE         (BLKSIZE*MAX_CONTINUE)  // Expect continue space
+
+uint64_t lba_marker_time;
+struct __attribute__((__packed__)) marked_block_data {
+    uint32_t lba;
+    uint64_t zero_padding[510];
+    uint64_t timestamp;
+    uint32_t crc;
+} bdata;
+
+struct mrdump_lba_handle {
+	struct mrdump_dev *dumpdev;
+	uint64_t allocsize;
+	uint64_t filesize;
+	unsigned int wlba;
+	unsigned int rlba;
+	int bidx;
+	int midx;
+	unsigned int blknum;
+	unsigned int block_lba[1024];
+	uint8_t data[EXSPACE];
+};
+
+static uint64_t ext4_lba_to_block_offset(uint32_t lba)
+{
+	return (uint64_t)lba * (uint64_t)BLKSIZE;
+}
+
+static bool check_block_valid(const struct mrdump_lba_handle *handle, uint32_t lba)
+{
+	mtk_wdt_restart();
+	if (!handle->dumpdev->read(handle->dumpdev, ext4_lba_to_block_offset(lba), (uint8_t *)&bdata, BLKSIZE)) {
+		voprintf_error(" Read BlockData failed\n");
+		return false;
+	}
+
+	if (bdata.lba != lba) {
+		voprintf_error(" Read BlockData LBA failed (c:%08x, v:%08x)\n", bdata.lba, lba);
+		return false;
+	}
+
+	if (bdata.timestamp != lba_marker_time) {
+		voprintf_error(" Read BlockData timestamp failed (c:%016x, v:%016x)\n", bdata.timestamp, lba_marker_time);
+		return false;
+	}
+
+	unsigned int crcval = crc32(0, Z_NULL, 0);
+	crcval = crc32(crcval, (void *)&bdata, (BLKSIZE - 4));
+	if (bdata.crc != crcval) {
+		voprintf_error("%s: Get BlockData crc32 error (c:%08x, v:%08x)\n", __func__, crcval, bdata.crc);
+		return false;
+	}
+
+	return true;
+}
+
+static int Get_Next_bidx(struct mrdump_lba_handle *handle, unsigned int moves)
+{
+	unsigned int mycrc;
+
+	if (handle->bidx == 1022) {
+		handle->rlba = handle->block_lba[handle->bidx];
+		if (!handle->dumpdev->read(handle->dumpdev, ext4_lba_to_block_offset(handle->rlba), (uint8_t *)handle->block_lba, BLKSIZE)) {
+			voprintf_error(" SDCard: Reading BlockLBA failed.\n");
+			return -1;
+		}
+		// check crc32
+		mycrc = crc32(0, Z_NULL, 0);
+		mycrc = crc32(mycrc, (void *)handle->block_lba, (BLKSIZE-4));
+		if (mycrc != handle->block_lba[1023]) {
+			voprintf_error(" Get next index crc32 error!\n");
+			return -1;
+		}
+		handle->bidx = 0;
+	} else {
+		handle->bidx+=moves;
+	}
+	return handle->bidx;
+}
+
+unsigned int Num_to_Join(const struct mrdump_lba_handle *handle, unsigned int idx)
+{
+	unsigned int i, j;
+	uint32_t lba;
+
+	for (i=0, j=0; i<MAX_CONTINUE; i++) {
+		lba = handle->block_lba[idx+i];
+		if ((lba - handle->block_lba[idx]) == i) {
+			mtk_wdt_restart();
+			if (!check_block_valid(handle, lba)) {
+				voprintf_error(" BlockData Verification failed\n");
+				return 0;
+			}
+			j++;
+			continue;
+		}
+		break;
+	}
+	return j;
+}
+
+// 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_lba_handle *handle, uint8_t *buf, uint32_t Length)
+{
+	int total;
+	unsigned int leftspace, mylen, reval;
+
+	total = BLKSIZE * handle->blknum;
+	leftspace = total - handle->midx;
+
+	// Check Length
+	if (Length > leftspace) {
+		mylen = leftspace;
+		reval = Length - leftspace;
+	} else {
+		mylen = Length;
+		reval = 0;
+	}
+
+	// Store
+	memcpy(handle->data + handle->midx, buf, mylen);
+	handle->midx += mylen;
+
+	// Write
+	if (handle->midx == total) {
+		if (!handle->dumpdev->write(handle->dumpdev, ext4_lba_to_block_offset(handle->wlba), handle->data, total)) {
+			voprintf_error(" SDCard: Write dump data failed.\n");
+			return -1;
+		}
+		handle->bidx = Get_Next_bidx(handle, handle->blknum);
+		if (handle->bidx < 0) {
+			voprintf_error(" SDCard: Reading bidx failed.\n");
+			return -1;
+		}
+		if (handle->bidx == 1022) {
+			handle->bidx = Get_Next_bidx(handle, handle->blknum);
+			if (handle->bidx < 0) {
+				voprintf_error(" SDCard: Reading 1022 bidx failed.\n");
+				return -1;
+			}
+		}
+		handle->blknum = Num_to_Join(handle, handle->bidx);
+		if (handle->blknum == 0)
+			return -1;
+		handle->wlba = handle->block_lba[handle->bidx];
+		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_lba_handle *handle = opaque_handle;
+
+	if ((handle->filesize + size) > handle->allocsize) {
+		voprintf_error(" dump size > allocated size. file-size %lld allocate-size %lld\n", handle->filesize + size, handle->allocsize);
+		return -1;
+	}
+	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, ext4_lba_to_block_offset(handle->wlba), 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;
+	ret = len;
+	Ptr = (uint8_t *)buf;
+	while (1) {
+		ret = Do_Store_or_Write(handle, Ptr, len);
+		if (ret < 0) {
+			voprintf_error(" SDCard: Store and Write failed.\n");
+			return -1;
+		} else if (ret == 0) {
+			break;
+		} else {
+			Ptr  += (len - ret);
+			len   = ret;
+		}
+	}
+	return size;
+}
+
+static inline uint16_t paf_version_extract(uint8_t pafinfo[MRDUMP_PAF_TOTAL_SIZE])
+{
+	return pafinfo[0] + (pafinfo[1] << 8);
+}
+
+static void dump_paf_info(uint8_t InfoLBA[MRDUMP_PAF_TOTAL_SIZE], const char *msg, ...)
+{
+	va_list ap;
+	va_start(ap, msg);
+	voprintf('E', msg, ap);
+	va_end(ap);
+
+	uint32_t paf_version = paf_version_extract(InfoLBA);
+	uint32_t paf_info_lba = *(uint32_t *)(InfoLBA + MRDUMP_PAF_INFO_LBA);
+	uint32_t paf_addr_lba = *(uint32_t *)(InfoLBA + MRDUMP_PAF_ADDR_LBA);
+	uint64_t paf_alloc_size = *(uint64_t *)(InfoLBA + MRDUMP_PAF_ALLOCSIZE);
+	uint64_t paf_coredump_size = *(uint64_t *)(InfoLBA + MRDUMP_PAF_COREDUMPSIZE);
+	uint64_t paf_timestamp = *(uint64_t *)(InfoLBA + MRDUMP_PAF_TIMESTAMP);
+	uint32_t paf_crc32 = *(uint32_t *)(InfoLBA + MRDUMP_PAF_CRC32);
+
+	voprintf_info(" pafile ver %u info-lba %u addr-lba %u alloc-size %llu coredump-size %llu timestamp %llx crc %x\n",
+		      paf_version, paf_info_lba, paf_addr_lba, paf_alloc_size, paf_coredump_size, paf_timestamp, paf_crc32);
+}
+
+int mrdump_ext4_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 InfoLBA[MRDUMP_PAF_TOTAL_SIZE];
+	unsigned int mycrc;
+
+	if (mrdump_dev == NULL) {
+		return -1;
+	}
+
+	voprintf_info("Output to DATA FS Partition %s\n", mrdump_dev->name);
+
+	// pre-work for ext4 LBA
+	bzero(InfoLBA, sizeof(InfoLBA));
+
+	// Error 1. InfoLBA starting address not available
+	if (mrdump_cb->output_fs_lbaooo == 0) {
+		voprintf_error(" Pre-Allocate has no LBA markers(lbaooo=%u). RAM-Dump stop!\n", mrdump_cb->output_fs_lbaooo);
+		return -1;
+	}
+	if (!mrdump_dev->read(mrdump_dev, ext4_lba_to_block_offset(mrdump_cb->output_fs_lbaooo), (uint8_t *)InfoLBA, sizeof(InfoLBA))) {
+		voprintf_error(" SDCard: Reading InfoLBA failed.\n");
+		return -1;
+	}
+
+	uint32_t paf_version = paf_version_extract(InfoLBA);
+	uint32_t paf_info_lba = *(uint32_t *)(InfoLBA + MRDUMP_PAF_INFO_LBA);
+	uint32_t paf_addr_lba = *(uint32_t *)(InfoLBA + MRDUMP_PAF_ADDR_LBA);
+	uint64_t paf_alloc_size = *(uint64_t *)(InfoLBA + MRDUMP_PAF_ALLOCSIZE);
+	uint64_t paf_coredump_size = *(uint64_t *)(InfoLBA + MRDUMP_PAF_COREDUMPSIZE);
+	uint64_t paf_timestamp = *(uint64_t *)(InfoLBA + MRDUMP_PAF_TIMESTAMP);
+	uint32_t paf_info_crc32 = *(uint32_t *)(InfoLBA + MRDUMP_PAF_CRC32);
+
+	if (paf_version != MRDUMP_PAF_VERSION) {
+		dump_paf_info(InfoLBA, " Unsupport PAF version %d (expected: %d)\n", paf_version, MRDUMP_PAF_VERSION);
+		return -1;
+	}
+	// Error 3. InfoLBA[EXT4_1ST_LBA] should be mrdump_cb->output_fs_lbaooo
+	if (mrdump_cb->output_fs_lbaooo != paf_info_lba) {
+		dump_paf_info(InfoLBA, " LBA Starting Address Error(LBA0=%u)! Abort!\n", paf_info_lba);
+		return -1;
+	}
+
+	// Error 4. EXT4_CORE_DUMP_SIZE is not zero --> want to hold 1st dump
+	if (paf_coredump_size != 0) {
+		dump_paf_info(InfoLBA, " CORE DUMP SIZE is not Zero! Abort!(coresize=%llu)\n", paf_coredump_size);
+		return -1;
+	}
+
+	// Error 5. EXT4_USER_FILESIZE is zero
+	if (paf_alloc_size == 0) {
+		dump_paf_info(InfoLBA, " Allocate file with zero size. Abort!(filesize=%llu)\n", paf_alloc_size);
+		return -1;
+	}
+
+	// get lba_marker_time as timestamp
+	lba_marker_time = paf_timestamp;
+
+	// Error 2. CRC not matched
+	mycrc = crc32(0L, Z_NULL, 0);
+	mycrc = crc32(mycrc, (const unsigned char*)InfoLBA, sizeof(InfoLBA) - 4);
+	if (mycrc != paf_info_crc32) {
+		dump_paf_info(InfoLBA, " InfoLBA CRC32 Error! Abort! (CRC1=0x%08x, CRC2=0x%08x)\n", mycrc, paf_info_crc32);
+		return -1;
+	}
+
+	struct mrdump_lba_handle *handle = memalign(16, sizeof(struct mrdump_lba_handle));
+	if (handle == NULL) {
+		voprintf_error("No enough memory.\n");
+		return -1;
+	}
+	memset(handle, 0, sizeof(struct mrdump_lba_handle));
+	handle->dumpdev = mrdump_dev;
+	handle->rlba = mrdump_cb->output_fs_lbaooo;
+	handle->allocsize = paf_alloc_size;
+
+	// Mark coredump as ULLONG_MAX to verify the unknown interrupt case during dumping data
+	*(uint64_t *)(InfoLBA + MRDUMP_PAF_COREDUMPSIZE) = ULLONG_MAX;
+
+	//calculate the CRC
+	mycrc = crc32(0L, Z_NULL, 0);
+	*(uint32_t *)(InfoLBA + MRDUMP_PAF_CRC32) = crc32(mycrc, (const unsigned char*)InfoLBA, MRDUMP_LBA_DATAONLY);
+
+	//update the coredump sizeand CRC
+	if (!handle->dumpdev->write(handle->dumpdev, ext4_lba_to_block_offset(paf_info_lba), (uint8_t *)InfoLBA, sizeof(InfoLBA))) {
+		voprintf_error(" SDCard: Write InfoLBA error.\n");
+		free(handle);
+		return -1;
+	}
+
+	// Starting Dumping Data
+	handle->rlba = paf_addr_lba;
+	if (!handle->dumpdev->read(handle->dumpdev, ext4_lba_to_block_offset(handle->rlba), (uint8_t *)handle->block_lba, BLKSIZE)) {
+		dump_paf_info(InfoLBA, " SDCard: Reading BlockLBA error.\n");
+		free(handle);
+		return -1;
+	}
+	handle->wlba = handle->block_lba[handle->midx];
+	handle->blknum = Num_to_Join(handle, handle->bidx);
+	if (handle->blknum == 0) {
+		voprintf_error("No continuous space.\n");
+		free(handle);
+		return -1;
+	}
+
+	voprintf_info(" Pre-Allocate starts at LBA: %u\n", paf_info_lba);
+	voprintf_info(" SYS_COREDUMP starts at LBA: %u\n", handle->wlba);
+
+	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 */
+		zf = NULL;
+	} else {
+		ok = false;
+	}
+
+	if (!ok) {
+		free(handle);
+		return -1;
+	}
+
+	voprintf_info(" SYS_COREDUMP ends at LBA: %u\n", handle->wlba);
+	voprintf_info(" Zip COREDUMP size is: %llu\n", handle->filesize);
+
+	// Record File Size...
+	*(uint64_t *)(InfoLBA + MRDUMP_PAF_COREDUMPSIZE) = handle->filesize;
+
+	mycrc = crc32(0L, Z_NULL, 0);
+	*(uint32_t *)(InfoLBA + MRDUMP_PAF_CRC32) = crc32(mycrc, (const unsigned char*)InfoLBA, MRDUMP_LBA_DATAONLY);
+
+	if (!handle->dumpdev->write(handle->dumpdev, ext4_lba_to_block_offset(paf_info_lba), (uint8_t *)InfoLBA, sizeof(InfoLBA))) {
+		voprintf_error(" SDCard: Write InfoLBA error.\n");
+		free(handle);
+		return -1;
+	}
+	free(handle);
+
+	mtk_wdt_restart();
+	mrdump_status_ok("OUTPUT:%s\nMODE:%s\n", "DATA_FS", mrdump_mode2string(mrdump_cb->crash_record.reboot_mode));
+	return 0;
+}
+

+ 548 - 0
app/mt_boot/aee/mrdump_dbgscript.c

@@ -0,0 +1,548 @@
+/* Copyright Statement:
+*
+* This software/firmware and related documentation ("MediaTek Software") are
+* protected under relevant copyright laws. The information contained herein
+* is confidential and proprietary to MediaTek Inc. and/or its licensors.
+* Without the prior written permission of MediaTek inc. and/or its licensors,
+* any reproduction, modification, use or disclosure of MediaTek Software,
+* and information contained herein, in whole or in part, shall be strictly prohibited.
+*/
+/* MediaTek Inc. (C) 2016. All rights reserved.
+*
+* BY OPENING THIS FILE, RECEIVER HEREBY UNEQUIVOCALLY ACKNOWLEDGES AND AGREES
+* THAT THE SOFTWARE/FIRMWARE AND ITS DOCUMENTATIONS ("MEDIATEK SOFTWARE")
+* RECEIVED FROM MEDIATEK AND/OR ITS REPRESENTATIVES ARE PROVIDED TO RECEIVER ON
+* AN "AS-IS" BASIS ONLY. MEDIATEK EXPRESSLY DISCLAIMS ANY AND ALL WARRANTIES,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED WARRANTIES OF
+* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE OR NONINFRINGEMENT.
+* NEITHER DOES MEDIATEK PROVIDE ANY WARRANTY WHATSOEVER WITH RESPECT TO THE
+* SOFTWARE OF ANY THIRD PARTY WHICH MAY BE USED BY, INCORPORATED IN, OR
+* SUPPLIED WITH THE MEDIATEK SOFTWARE, AND RECEIVER AGREES TO LOOK ONLY TO SUCH
+* THIRD PARTY FOR ANY WARRANTY CLAIM RELATING THERETO. RECEIVER EXPRESSLY ACKNOWLEDGES
+* THAT IT IS RECEIVER'S SOLE RESPONSIBILITY TO OBTAIN FROM ANY THIRD PARTY ALL PROPER LICENSES
+* CONTAINED IN MEDIATEK SOFTWARE. MEDIATEK SHALL ALSO NOT BE RESPONSIBLE FOR ANY MEDIATEK
+* SOFTWARE RELEASES MADE TO RECEIVER'S SPECIFICATION OR TO CONFORM TO A PARTICULAR
+* STANDARD OR OPEN FORUM. RECEIVER'S SOLE AND EXCLUSIVE REMEDY AND MEDIATEK'S ENTIRE AND
+* CUMULATIVE LIABILITY WITH RESPECT TO THE MEDIATEK SOFTWARE RELEASED HEREUNDER WILL BE,
+* AT MEDIATEK'S OPTION, TO REVISE OR REPLACE THE MEDIATEK SOFTWARE AT ISSUE,
+* OR REFUND ANY SOFTWARE LICENSE FEES OR SERVICE CHARGE PAID BY RECEIVER TO
+* MEDIATEK FOR SUCH MEDIATEK SOFTWARE AT ISSUE.
+*/
+
+#include <stdarg.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "aee.h"
+#include "mrdump_private.h"
+
+/* mdrump string file to uart log*/
+/* #define DEBUG_MRDUMP_PRINTF */
+
+#define MRDUMP_STR_BUFF_LEN (1024*100) /* 100Kib*/
+static struct _mrdump_string_buf {
+	char* buf;
+	int len;
+	int wpos;
+} mrdump_string_buf = {
+	.buf = NULL,
+	.len = 0,
+	.wpos = 0
+};
+
+extern int g_is_64bit_kernel;
+
+static void init_mrdump_string_buf(void)
+{
+	dprintf(CRITICAL, "%s\n", __func__);
+
+	if (mrdump_string_buf.buf) {
+		dprintf(CRITICAL, "[ERROR]MT-RAMDUMP: mrdump_string_buf has already initialized(mrdump_string_wbuf.buf!=NULL)\n");
+		return;
+	}
+	mrdump_string_buf.buf = malloc(MRDUMP_STR_BUFF_LEN);
+	if (!mrdump_string_buf.buf) {
+		dprintf(CRITICAL, "[ERROR]MT-RAMDUMP: faild to allocate mrdump_string_buf\n");
+		return;
+	}
+	memset(mrdump_string_buf.buf, 0, MRDUMP_STR_BUFF_LEN);
+	mrdump_string_buf.len = MRDUMP_STR_BUFF_LEN;
+	mrdump_string_buf.wpos = 0;
+}
+
+static void uninit_mrdump_string_buf(void)
+{
+	dprintf(CRITICAL, "%s\n", __func__);
+
+	if(mrdump_string_buf.buf)
+		free(mrdump_string_buf.buf);
+	memset(&mrdump_string_buf, 0, sizeof(mrdump_string_buf));
+}
+
+static int mrdump_vsprintf(const char *fmt, va_list ap)
+{
+	int wcnt, wmax;
+	char* buf;
+
+	if(mrdump_string_buf.buf == NULL)
+		return 0;
+
+	if(mrdump_string_buf.len<=mrdump_string_buf.wpos) {
+		dprintf(CRITICAL, "Error: exceed mrdump_string_buf(%d,%d)\n", mrdump_string_buf.len, mrdump_string_buf.wpos);
+		return 0;
+	}
+
+	buf = &mrdump_string_buf.buf[mrdump_string_buf.wpos];
+	wmax = mrdump_string_buf.len-mrdump_string_buf.wpos;
+
+	wcnt = vsnprintf(buf, wmax, fmt, ap);
+	if(wcnt < 0) {
+		dprintf(CRITICAL, "Error: invalid wcnt(%d)\n", wcnt);
+		return 0;
+	}
+	mrdump_string_buf.wpos += wcnt;
+
+#ifdef DEBUG_MRDUMP_PRINTF /* cmm to uart log */
+	dputs(CRITICAL,buf);
+#endif
+
+	return wcnt;
+}
+
+static int mrdump_printf(const char *fmt, ...)
+{
+	int w;
+	va_list args;
+	va_start(args, fmt);
+	w = mrdump_vsprintf(fmt, args);
+	va_end(args);
+	return w;
+}
+
+static struct mrdump_machdesc* aee_get_machdesc_from_cb(struct mrdump_control_block *mrdump_cblock)
+{
+	if (mrdump_cblock)
+		return &mrdump_cblock->machdesc;
+
+	dprintf(CRITICAL, "Error: aee_get_machdesc_from_cb\n");
+	return NULL;
+}
+
+static struct mrdump_ksyms_param* aee_get_ksyms_from_cb(struct mrdump_control_block *mrdump_cblock)
+{
+	struct mrdump_machdesc* mach;
+
+	if (mrdump_cblock) {
+		mach = &mrdump_cblock->machdesc;
+		if(mach)
+			return &mach->kallsyms;
+	}
+
+	dprintf(CRITICAL, "Error: aee_get_ksyms_from_cb\n");
+	return NULL;
+}
+
+static void print_file_dialog_cmm(char* title, char* msg, char* file_path)
+{
+	mrdump_printf("	dialog.view\n");
+	mrdump_printf("	(\n");
+	mrdump_printf("          header \"%s\"\n", title);
+	mrdump_printf("          pos 0. 0. 30. 3.\n");
+	mrdump_printf("          box \"%s\"\n", msg);
+	mrdump_printf("          pos 1. 1. 20. 1.\n");
+	mrdump_printf("%s:     defedit \"\" \"\"\n", file_path);
+	mrdump_printf("          pos 22. 1. 7. 1.\n");
+	mrdump_printf("          button \"Browse...\"\n");
+	mrdump_printf("          (\n");
+	mrdump_printf("            dialog.file \"*.*\"\n");
+	mrdump_printf("            entry %%line &file\n");
+	mrdump_printf("            dialog.set %s \"&file\"\n", file_path);
+	mrdump_printf("          )\n");
+	mrdump_printf("          pos 6. 3. 7. 1.\n");
+	mrdump_printf("          defbutton \"Ok\"\n");
+	mrdump_printf("          (            \n");
+	mrdump_printf("            &%s=dialog.string(%s)\n", file_path, file_path);
+	mrdump_printf("            continue\n");
+	mrdump_printf("          )\n");
+	mrdump_printf("          pos 17. 3. 7. 1.\n");
+	mrdump_printf("          button \"Cancel\"  \"continue\"\n");
+	mrdump_printf("	)\n");
+	mrdump_printf("	STOP\n");
+	mrdump_printf("	dialog.end\n");
+}
+
+extern bool ram_console_get_kaslr_offset(uint64_t* kaslr_offset);
+static void print_pre_cmm(struct mrdump_control_block *mrdump_cblock)
+{
+	struct mrdump_machdesc* machd = aee_get_machdesc_from_cb(mrdump_cblock);
+	uint64_t kaslr_offset = 0;
+	bool kaslr_valid;
+	kaslr_valid = ram_console_get_kaslr_offset(&kaslr_offset);
+
+	mrdump_printf("B::AREA\n");
+
+	mrdump_printf("local &vmlinux_file\n");
+	mrdump_printf("&vmlinux_file=\".\\vmlinux\"\n");
+	mrdump_printf("IF OS.FILE(\"&vmlinux_file\")!=TRUE()\n");
+	mrdump_printf("(\n");
+	print_file_dialog_cmm("Load Vmlinux", "File path", "vmlinux_file");
+	mrdump_printf(")\n\n");
+
+	mrdump_printf("local &ramdump_elf_core_file\n");
+	mrdump_printf("&ramdump_elf_core_file=\".\\SYS_COREDUMP\"\n");
+	mrdump_printf("IF OS.FILE(\"&ramdump_elf_core_file\")!=TRUE()\n");
+	mrdump_printf("(\n");
+	print_file_dialog_cmm("Load RAMDUMP(Core ELF)", "File path", "ramdump_elf_core_file");
+	mrdump_printf(")\n\n");
+
+	/*T32 cmm: pre-setting*/
+	mrdump_printf("sys.res\n");
+	mrdump_printf("sys.cpu %s\n", g_is_64bit_kernel ? "CortexA53":"CortexA7MPCore");
+	mrdump_printf("sys.config.cn %d\n", machd->nr_cpus);
+	mrdump_printf("core.num %d\n", machd->nr_cpus);
+	mrdump_printf("sys.o mmuspaces on\n");
+	mrdump_printf("sys.u\n");
+	mrdump_printf("title os.pwd()\n\n");
+
+	mrdump_printf("d.load.e &vmlinux_file 0x%llx\n", kaslr_offset);
+	mrdump_printf("&vmlinux_banner=V.STRING(linux_banner)\n");
+	mrdump_printf("&vmlinux_banner_len=STRing.LENgth(\"&vmlinux_banner\")\n");
+	mrdump_printf("&vmlinux_build_time=STRing.SPLIT(V.STRING(&linux_banner[200]),\"#\", -1)\n");
+
+	mrdump_printf("d.load.e &ramdump_elf_core_file /nc /ny /physload\n\n");
+	if(kaslr_valid)
+		mrdump_printf("PRINT \"OK!, kaslr_offset is valid\"\n");
+	else
+		mrdump_printf("PRINT %%ERROR \"kaslr_offset IS NOT valid\"\n");
+	mrdump_printf("\n");
+}
+
+static void print_post_cmm(struct mrdump_control_block *mrdump_cblock)
+{
+	struct mrdump_crash_record* cr;
+	struct mrdump_machdesc* mach;
+	if (mrdump_cblock) {
+		mach = &mrdump_cblock->machdesc;
+		cr = &mrdump_cblock->crash_record;
+	}
+	else {
+		mrdump_printf(";error mrdump_core_context_to_klog : mrdump_cblock=NULL\n");
+		return;
+	}
+
+	mrdump_printf("; select fault cpu\n");
+	mrdump_printf("core.select %u\n", cr->fault_cpu);
+
+	/* the common address range for all processes and is everything above the process address range
+	whole kernel address space including module */
+	if (g_is_64bit_kernel) {
+		mrdump_printf("mmu.format linuxswap3 swapper_pg_dir 0x%016llx--0xffffffffffffffff 0x%016llx\n",
+		mach->page_offset, mach->dram_start);
+		/* 0xFFFFFF8000000000--0xFFFFFFFFFFFFFFFF */
+		mrdump_printf("trans.common 0x%016llx--0xffffffffffffffff \n",
+		MIN(mach->page_offset, mach->modules_start));
+	}
+	else {
+		mrdump_printf("mmu.format linuxswap3 swapper_pg_dir 0x%08x--0xffffffff 0x%x\n",
+		(uint32_t)(mach->page_offset & 0xffffffff), (uint32_t)(mach->dram_start & 0xffffffff));
+		/* trans.common 0xBF000000--0xFFFFFFFF */
+		mrdump_printf("trans.common 0x%08x--0xffffffff \n",
+		(uint32_t)(MIN(mach->page_offset, mach->modules_start) & 0xffffffff));
+	}
+	mrdump_printf("trans.tw on\n");
+	mrdump_printf("trans.on\n");
+	mrdump_printf("mmu.scan\n\n");
+	/* show kernel pagetable */
+	mrdump_printf("mmu.list.pagetable 0x%llx\n\n", mach->page_offset);
+
+	if (g_is_64bit_kernel) {
+		mrdump_printf("; load the awareness for Linux-3.x on ARM\n");
+		mrdump_printf("TASK.CONFIG ~~/demo/arm64/kernel/linux/linux-3.x/linux3.t32\n");
+		mrdump_printf("; load Linux menu:\n");
+		mrdump_printf("MENU.ReProgram ~~/demo/arm64/kernel/linux/linux-3.x/linux.men\n");
+		mrdump_printf("task.dmesg\n\n");
+	}
+	else {
+		mrdump_printf("; load the awareness for Linux-3.x on ARM\n");
+		mrdump_printf("TASK.CONFIG ~~/demo/arm/kernel/linux/linux-3.x/linux3.t32\n");
+		mrdump_printf("; load Linux menu:\n");
+		mrdump_printf("MENU.ReProgram ~~/demo/arm/kernel/linux/linux-3.x/linux.men\n");
+		mrdump_printf("task.dmesg\n\n");
+	}
+}
+
+static void print_verify_view_cmm(struct mrdump_crash_record* cr)
+{
+	/* verify linux_banner */
+	mrdump_printf("&ramdump_banner=V.STRING(linux_banner)\n");
+	mrdump_printf("&t32_max_strlen=255.\n");
+	mrdump_printf("IF &vmlinux_banner_len>=&t32_max_strlen\n");
+	mrdump_printf("(\n");
+	mrdump_printf("\t&ramdump_build_time=STRing.SPLIT(V.STRING(&linux_banner[200]),\"#\", -1)\n\n");
+
+	mrdump_printf("\tPRINT %%ERROR \"vmlinux banner : [#&vmlinux_build_time] &vmlinux_banner\"\n");
+	mrdump_printf("\tPRINT %%ERROR \"ramdump banner : [#&ramdump_build_time] &ramdump_banner\"\n\n");
+
+	mrdump_printf("\tIF (\"&vmlinux_banner\"!=\"&ramdump_banner\")\n");
+	mrdump_printf("\t(\n");
+	mrdump_printf("\t	PRINT %%ERROR \"!!!!!!!!! No maching vmlinux symbol and dump binary...\"\n");
+	mrdump_printf("\t	PRINT %%ERROR \"or check your mmu settting...\"\n");
+	mrdump_printf("\t	ENDDO\n");
+	mrdump_printf("\t)\n\n");
+
+	mrdump_printf("\tIF (\"&ramdump_build_time\"!=\"&vmlinux_build_time\")\n");
+	mrdump_printf("\t(\n");
+	mrdump_printf("\t	PRINT %%ERROR \"!!!!!!!!! No maching build time !!!!!!!!!\"\n");
+	mrdump_printf("\t	PRINT %%ERROR \"check binary and vmlinux build time\"\n");
+	mrdump_printf("\t	PRINT %%ERROR \"Symbole build time : #&vmlinux_build_time\"\n");
+	mrdump_printf("\t	PRINT %%ERROR \"RAMDUM build time  : #&ramdump_build_time\"\n");
+	mrdump_printf("\t)\n\n");
+	mrdump_printf(")\n");
+
+	mrdump_printf("ELSE\n");
+	mrdump_printf("(\n");
+	mrdump_printf("\tPRINT %%ERROR \"vmlinux banner : &vmlinux_banner\"\n");
+	mrdump_printf("\tPRINT %%ERROR \"ramdump banner : &ramdump_banner\"\n");
+	mrdump_printf("\tIF (\"&vmlinux_banner\"!=\"&ramdump_banner\")\n");
+	mrdump_printf("\t(\n");
+	mrdump_printf("\t\tPRINT %%ERROR \"!!!!!!!!! No maching vmlinux symbol and dump binary...\"\n");
+	mrdump_printf("\t\tPRINT %%ERROR \"or check your mmu settting...\"\n");
+	mrdump_printf("\t\tENDDO\n");
+	mrdump_printf("\t)\n");
+	mrdump_printf(")\n");
+
+	/* windows layout */
+	mrdump_printf(";y.l.sec\n");
+	mrdump_printf("l\nr\nf\n");
+	mrdump_printf("WinPOS 0.0 0.0 100. 6. 0. 0. W000\n");
+	mrdump_printf("AREA\n");
+	mrdump_printf("ENDDO\n");
+}
+
+static void print_arm64regs_cmm(struct mrdump_crash_record* cr, int nr_cpu)
+{
+	char msg[128+32];
+	struct arm64_ctrl_regs* pcore_sysr;
+	uint64_t* pcore_cpur;
+
+	int i, cpu;
+	if (!cr)
+		return;
+
+	if (snprintf(msg, sizeof(msg), ";%s\n", cr->msg)>0)
+		mrdump_printf(msg);
+
+	for (cpu=0; cpu<nr_cpu; cpu++) {
+		mrdump_printf("; CPU%d's Registers\n", cpu);
+		mrdump_printf("core.select %d\n", cpu);
+
+		/* print cpu registers */
+		pcore_cpur = &cr->cpu_regs[cpu].arm64_regs[0];
+		for(i=0; i<31; i++) {
+			mrdump_printf("R.S X%d 0x%016llx\n", i, pcore_cpur[i]);
+		}
+		mrdump_printf("R.S SP 0x%016llx\n", pcore_cpur[i++]);
+		mrdump_printf("R.S PC 0x%016llx\n", pcore_cpur[i++]);
+		mrdump_printf("R.S CPSR 0x%llx\n", pcore_cpur[i++]/*pstate*/);
+		mrdump_printf("; END CPU Regs\n");
+
+		/*MMU registers*/
+		pcore_sysr = &cr->cpu_creg[cpu].arm64_creg;
+		mrdump_printf("; CPU%d's MMU & System Control Registers\n", cpu);
+
+		mrdump_printf("PER.Set SPR:0x30200 %%QUAD 0x%016llx ;TTBR0_EL1\n", pcore_sysr->ttbr0_el1);
+		mrdump_printf("PER.Set SPR:0x34200 %%QUAD 0x%016llx ;TTBR0_EL2\n", pcore_sysr->ttbr0_el2);
+		mrdump_printf("PER.Set SPR:0x36200 %%QUAD 0x%016llx ;TTBR0_EL3\n", pcore_sysr->ttbr0_el3);
+
+		mrdump_printf("PER.Set SPR:0x30201 %%QUAD 0x%016llx ;TTBR1_EL1\n", pcore_sysr->ttbr1_el1);
+
+		mrdump_printf("PER.Set SPR:0x30100 %%QUAD 0x%08x ;SCTLR_EL1\n", pcore_sysr->sctlr_el1);
+		mrdump_printf("PER.Set SPR:0x34100 %%QUAD 0x%08x ;SCTLR_EL2\n", pcore_sysr->sctlr_el2);
+		mrdump_printf("PER.Set SPR:0x36100 %%QUAD 0x%08x ;SCTLR_EL3\n", pcore_sysr->sctlr_el3);
+
+		mrdump_printf("PER.Set SPR:0x30202 %%QUAD 0x%016llx ;TCR_EL1\n", pcore_sysr->tcr_el1);
+		mrdump_printf("PER.Set SPR:0x34202 %%QUAD 0x%016llx ;TCR_EL2\n", pcore_sysr->tcr_el2);
+		mrdump_printf("PER.Set SPR:0x36202 %%QUAD 0x%016llx ;TCR_EL3\n", pcore_sysr->tcr_el3);
+
+		for(i=0; i<4; i++) {
+			mrdump_printf("R.S sp_el%d 0x%016llx\n", i, pcore_sysr->sp_el[i]);
+		}
+		mrdump_printf("; END MMU & SCTLR\n");
+	}
+}
+
+static void print_arm32regs_cmm(struct mrdump_crash_record* cr, int nr_cpu)
+{
+	char msg[128+32];
+	struct arm32_ctrl_regs* pcore_sysr;
+	uint32_t * pcore_cpur;
+
+	int i, cpu;
+	if (!cr)
+		return;
+
+	if (snprintf(msg, sizeof(msg), ";%s\n", cr->msg)>0)
+		mrdump_printf(msg);
+
+	for (cpu=0; cpu<nr_cpu; cpu++) {
+		mrdump_printf("; CPU%d's Registers\n", cpu);
+		mrdump_printf("core.select %d\n", cpu);
+
+		/* print cpu registers */
+		pcore_cpur = &cr->cpu_regs[cpu].arm32_regs[0];
+		for(i=0; i<15; i++) {
+			mrdump_printf("R.S r%d 0x%08x\n", i, pcore_cpur[i]);
+		}
+		i=15;
+		mrdump_printf("R.S PC 0x%08x\n", pcore_cpur[i++]);
+		mrdump_printf("R.S CPSR 0x%08x\n", pcore_cpur[i++]/*pstate*/);
+		mrdump_printf("; END CPU Regs\n");
+
+		/*MMU registers*/
+		pcore_sysr = &cr->cpu_creg[cpu].arm32_creg;
+		mrdump_printf("; CPU%d's MMU & System Control Registers\n", cpu);
+		mrdump_printf("PER.Set.simple C15:0x1 %%Long 0x%08x ;SCTRL\n", pcore_sysr->sctlr);
+		mrdump_printf("PER.Set.simple C15:0x202 %%Long 0x%08x ;TTBCR\n",  (uint32_t)pcore_sysr->ttbcr);
+		mrdump_printf("PER.Set.simple C15:0x2 %%Long 0x%08x ;TTBR0\n",  (uint32_t)pcore_sysr->ttbr0);
+		mrdump_printf("PER.Set.simple C15:0x102 %%Long 0x%08x ;TTBR1\n",  (uint32_t)pcore_sysr->ttbr1);
+		mrdump_printf("; END MMU & SCTLR\n");
+	}
+}
+
+static void print_mrdump_machdesc(struct mrdump_control_block *mrdump_cblock)
+{
+	struct mrdump_machdesc* mach;
+	struct mrdump_ksyms_param* kallsym;
+	char tag[5];
+	if (mrdump_cblock) {
+		mach = &mrdump_cblock->machdesc;
+		kallsym = &mach->kallsyms;
+	}
+	else {
+		mrdump_printf(";error mrdump_core_context_to_klog : mrdump_cblock=NULL\n");
+		return;
+	}
+
+	mrdump_printf(";\n;*** mrdump_machdesc ***\n");
+	mrdump_printf(";nr_cpus=%u\n", mach->nr_cpus);
+
+	mrdump_printf(";page_offset = 0x%llx\n", mach->page_offset);
+	mrdump_printf(";high_memory = 0x%llx\n", mach->high_memory);
+
+	mrdump_printf(";kimage_vaddr = 0x%llx\n", mach->kimage_vaddr);
+	mrdump_printf(";dram_start = 0x%llx\n",  mach->dram_start);
+	mrdump_printf(";dram_end = 0x%llx\n", mach->dram_end);
+	mrdump_printf(";kimage_stext = 0x%llx\n", mach->kimage_stext);
+	mrdump_printf(";kimage_etext = 0x%llx\n", mach->kimage_etext);
+	mrdump_printf(";kimage_stext_real = 0x%llx\n", mach->kimage_stext_real);
+	mrdump_printf(";kimage_voffset = 0x%llx\n", mach->kimage_voffset);
+	mrdump_printf(";kimage_sdata = 0x%llx\n", mach->kimage_sdata);
+	mrdump_printf(";kimage_edata = 0x%llx\n", mach->kimage_edata);
+
+	mrdump_printf(";vmalloc_start = 0x%llx\n", mach->vmalloc_start);
+	mrdump_printf(";vmalloc_end = 0x%llx\n", mach->vmalloc_end);
+
+	mrdump_printf(";module_start = 0x%llx\n", mach->modules_start);
+	mrdump_printf(";module_end = 0x%llx\n", mach->modules_end);
+
+	mrdump_printf(";phys_offset = 0x%llx\n",  mach->phys_offset);
+	mrdump_printf(";master_page_table = 0x%llx\n", mach->master_page_table);
+
+	mrdump_printf(";memmap = 0x%llx\n", mach->memmap);
+
+	mrdump_printf(";dfdmem_pa = 0x%llx\n", mach->dfdmem_pa);
+	memcpy(tag, kallsym->tag,4);
+	tag[4] = '\0';
+	mrdump_printf(";ksyms.tag=%s\n", tag);
+
+	mrdump_printf(";ksyms.flag=0x%x(%s)\n", kallsym->flag, kallsym->flag==1?"KSYM_32":"KSYM_64");
+	mrdump_printf(";ksyms.crc=0x%x\n", kallsym->crc);
+	mrdump_printf(";ksyms.start_addr=0x%llx\n", kallsym->start_addr);
+	mrdump_printf(";ksyms.size=0x%x\n", kallsym->size);
+	mrdump_printf(";ksyms.address_off=0x%x\n", kallsym->addresses_off);
+	mrdump_printf(";ksyms.num_syms_off=0x%x\n", kallsym->num_syms_off);
+	mrdump_printf(";ksyms.names_off=0x%x\n", kallsym->names_off);
+	mrdump_printf(";ksyms.markers_off=0x%x\n",  kallsym->markers_off);
+	mrdump_printf(";ksyms.token_table_off=0x%x\n", kallsym->token_table_off);
+	mrdump_printf(";ksyms.token_index_off=0x%x\n", kallsym->token_index_off);
+}
+
+static void gen_cmm(struct mrdump_control_block *mrdump_cblock)
+{
+	struct mrdump_crash_record *crash_record;
+
+	if (mrdump_cblock) {
+		crash_record = &mrdump_cblock->crash_record;
+	}
+	else {
+		dprintf(CRITICAL, "error mrdump_core_context_to_klog : mrdump_cblock=NULL\n");
+		return;
+	}
+	dprintf(CRITICAL, "%s:mrdump_cblock=%p, crach_record=%p\n",__func__, mrdump_cblock, crash_record);
+	dprintf(CRITICAL, "crash_recode msg: %s\n", crash_record->msg);
+#if 0 /* show mem layout */
+	print_mrdump_machdesc(mrdump_cblock);
+#endif
+	mrdump_printf(";******************************************************\n");
+	mrdump_printf(";* CMM for Linux arch=%s [%s]*\n",
+	g_is_64bit_kernel ? "arm64":"arm(32)", crash_record->msg);
+	mrdump_printf(";******************************************************\n");
+
+	print_pre_cmm(mrdump_cblock);
+	if(g_is_64bit_kernel)
+		print_arm64regs_cmm(&mrdump_cblock->crash_record, mrdump_cblock->machdesc.nr_cpus);
+	else
+		print_arm32regs_cmm(&mrdump_cblock->crash_record, mrdump_cblock->machdesc.nr_cpus);
+
+	mrdump_printf("; select fault cpu\n");
+	mrdump_printf("core.select %u\n", mrdump_cblock->crash_record.fault_cpu);
+
+	print_post_cmm(mrdump_cblock);
+	print_verify_view_cmm(&mrdump_cblock->crash_record);
+
+	mrdump_printf(";******************************************************\n");
+	mrdump_printf(";*                    End CMM                          \n");
+	mrdump_printf(";******************************************************\n");
+}
+
+static void mrdump_cmm_gen(struct mrdump_control_block *mrdump_cblock)
+{
+	init_mrdump_string_buf();
+	gen_cmm(mrdump_cblock);
+}
+
+struct kzip_addlist *mrdump_memlist_fill_cmm(struct mrdump_control_block *mrdump_cblock)
+{
+	if (!mrdump_cblock)
+		return NULL;
+
+	mrdump_cmm_gen(mrdump_cblock);
+	if (mrdump_string_buf.buf && mrdump_string_buf.wpos > 0)
+	{
+		struct kzip_addlist *memlist = malloc(sizeof(struct kzip_addlist) * 2);
+		if (memlist == NULL)
+			return NULL;
+
+		memlist[0].address = (uint64_t)(uintptr_t) mrdump_string_buf.buf;
+		memlist[0].size = mrdump_string_buf.wpos;
+		memlist[0].type = MEM_NO_MAP;
+		memlist[0].memmap = 0;
+		memlist[0].pageflags = 0;
+		memlist[0].struct_page_size = 0;
+		memlist[1].address = 0;
+		memlist[1].size = 0;
+		memlist[1].type = MEM_NO_MAP;
+		memlist[1].memmap = 0;
+		memlist[1].pageflags = 0;
+		memlist[1].struct_page_size = 0;
+		return memlist;
+	}
+	return NULL;
+}
+
+void mrdump_memlist_free_cmm(struct kzip_addlist *memlist)
+{
+	uninit_mrdump_string_buf();
+	free(memlist);
+}

+ 150 - 0
app/mt_boot/aee/mrdump_dconfig.c

@@ -0,0 +1,150 @@
+/* Copyright Statement:
+*
+* This software/firmware and related documentation ("MediaTek Software") are
+* protected under relevant copyright laws. The information contained herein
+* is confidential and proprietary to MediaTek Inc. and/or its licensors.
+* Without the prior written permission of MediaTek inc. and/or its licensors,
+* any reproduction, modification, use or disclosure of MediaTek Software,
+* and information contained herein, in whole or in part, shall be strictly prohibited.
+*/
+/* MediaTek Inc. (C) 2016. All rights reserved.
+*
+* BY OPENING THIS FILE, RECEIVER HEREBY UNEQUIVOCALLY ACKNOWLEDGES AND AGREES
+* THAT THE SOFTWARE/FIRMWARE AND ITS DOCUMENTATIONS ("MEDIATEK SOFTWARE")
+* RECEIVED FROM MEDIATEK AND/OR ITS REPRESENTATIVES ARE PROVIDED TO RECEIVER ON
+* AN "AS-IS" BASIS ONLY. MEDIATEK EXPRESSLY DISCLAIMS ANY AND ALL WARRANTIES,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED WARRANTIES OF
+* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE OR NONINFRINGEMENT.
+* NEITHER DOES MEDIATEK PROVIDE ANY WARRANTY WHATSOEVER WITH RESPECT TO THE
+* SOFTWARE OF ANY THIRD PARTY WHICH MAY BE USED BY, INCORPORATED IN, OR
+* SUPPLIED WITH THE MEDIATEK SOFTWARE, AND RECEIVER AGREES TO LOOK ONLY TO SUCH
+* THIRD PARTY FOR ANY WARRANTY CLAIM RELATING THERETO. RECEIVER EXPRESSLY ACKNOWLEDGES
+* THAT IT IS RECEIVER'S SOLE RESPONSIBILITY TO OBTAIN FROM ANY THIRD PARTY ALL PROPER LICENSES
+* CONTAINED IN MEDIATEK SOFTWARE. MEDIATEK SHALL ALSO NOT BE RESPONSIBLE FOR ANY MEDIATEK
+* SOFTWARE RELEASES MADE TO RECEIVER'S SPECIFICATION OR TO CONFORM TO A PARTICULAR
+* STANDARD OR OPEN FORUM. RECEIVER'S SOLE AND EXCLUSIVE REMEDY AND MEDIATEK'S ENTIRE AND
+* CUMULATIVE LIABILITY WITH RESPECT TO THE MEDIATEK SOFTWARE RELEASED HEREUNDER WILL BE,
+* AT MEDIATEK'S OPTION, TO REVISE OR REPLACE THE MEDIATEK SOFTWARE AT ISSUE,
+* OR REFUND ANY SOFTWARE LICENSE FEES OR SERVICE CHARGE PAID BY RECEIVER TO
+* MEDIATEK FOR SUCH MEDIATEK SOFTWARE AT ISSUE.
+*/
+
+#include <pal_log.h>
+#include <pal_typedefs.h>
+#include <platform/verified_boot.h>
+#include <stdlib.h>
+#include <string.h>
+#include <verified_boot_common.h>
+#include <dev/mrdump.h>
+
+/* mrdump flow in dconfig */
+#if MTK_MRDUMP_SUPPORT == 2
+
+#define DCONFIG_PART "boot_para"
+#define DCONFIG_1STIMG_NAME "dconfig"
+#define DCONFIG_HEADER_SIZE 512
+#define DCONFIG_PLENV_SIZE 1024
+
+#ifdef MTK_SECURITY_SW_SUPPORT
+static uint8_t socid_chip[SOC_ID_LEN] = {0};
+#endif
+
+#define PLENV_SIG_SIZE 8
+#define PLENV_MRDUMP_STR "mrdump_enable=yes"
+#define PLENV_MRDUMP_LEN 18
+
+extern int mboot_common_load_part(char *part_name, char *img_name, unsigned long addr);
+
+static int mrdump_get_socid_cert(void)
+{
+	uint8_t *dconfig_hdr = NULL;
+	uint8_t *plenv = NULL;
+	int len = 0;
+
+#ifdef MTK_SECURITY_SW_SUPPORT
+	uint32_t sec_ret = sec_img_auth_init(DCONFIG_PART, DCONFIG_1STIMG_NAME,
+					     GET_SOCID_FROM_CERT2);
+	if (sec_ret) {
+		pal_log_err("%s: dconfig image auth init failed (0x%x)\n", __func__, sec_ret);
+		return MRDUMP_SEC_IMG_AUTH_INIT_ERROR;
+	}
+#endif
+
+	dconfig_hdr = malloc(DCONFIG_HEADER_SIZE + DCONFIG_PLENV_SIZE);
+	if (dconfig_hdr == NULL) {
+		pal_log_err("%s: not enough memory\n", __func__);
+		return MRDUMP_DCONFIG_MALLOC_ERROR;
+	}
+
+	len = mboot_common_load_part(DCONFIG_PART, DCONFIG_1STIMG_NAME,
+				     (unsigned long)dconfig_hdr);
+	if (len <= 0) {
+		pal_log_err("%s: partition_read failed, return value %d\n", __func__, len);
+		free(dconfig_hdr);
+		return MRDUMP_MBOOT_LOAD_PART_ERROR;
+	}
+
+#ifdef MTK_SECURITY_SW_SUPPORT
+	sec_ret = sec_img_auth(dconfig_hdr, len);
+	if (sec_ret) {
+		pal_log_err("%s: dconfig image verify failed (0x%x)\n", __func__, sec_ret);
+		free(dconfig_hdr);
+		return MRDUMP_DCONFIG_IMG_VERIFY_ERROR;
+	}
+
+	uint8_t socid_cert[SOC_ID_LEN] = {0};
+	sec_ret = get_socid_cert(socid_cert, SOC_ID_LEN);
+	if (sec_ret) {
+		pal_log_err("%s: unable to get socid from certed image (0x%x)\n", __func__, sec_ret);
+		free(dconfig_hdr);
+		return MRDUMP_DCONFIG_SOCID_CERT_ERROR;
+	}
+
+	if (strncmp((char *)socid_chip, (char *)socid_cert, SOC_ID_LEN) != 0) {
+		pal_log_err("%s: socid mismatched\n", __func__);
+		free(dconfig_hdr);
+		return MRDUMP_DCNFIG_SOCID_MISMATCH;
+	}
+#endif
+
+	char *mrdump_enable_str = (char *)dconfig_hdr + DCONFIG_HEADER_SIZE + PLENV_SIG_SIZE;
+	if (strncmp(mrdump_enable_str, PLENV_MRDUMP_STR, PLENV_MRDUMP_LEN) != 0) {
+		pal_log_err("%s: not a valid mrdump enabled image\n", __func__);
+		free(dconfig_hdr);
+		return MRDUMP_NOT_VALID_IMG;
+	}
+
+	pal_log_info("mrdump_get_socid_cert done.\n");
+	free(dconfig_hdr);
+	return MRDUMP_SUCCESS_ENABLE;
+}
+
+int mrdump_check_enable(void)
+{
+#ifndef MTK_SECURITY_SW_SUPPORT
+	return 0;
+#else
+	uint32_t sec_ret = get_socid_chip(socid_chip, SOC_ID_LEN);
+
+	if (sec_ret) {
+		pal_log_err("%s: unable to get socid from chip (0x%x)\n", __func__, sec_ret);
+		return MRDUMP_NO_SOCID_FROM_CHIP;
+	}
+
+	return (mrdump_get_socid_cert());
+#endif
+}
+
+/* mrdump flow not in dconfig */
+#elif MTK_MRDUMP_SUPPORT == 1
+
+int mrdump_check_enable(void)
+{
+	return MRDUMP_ALWAYS_ENABLE;
+}
+
+#else
+
+#error Unknown MTK_MRDUMP_SUPPORT value
+
+#endif

+ 107 - 0
app/mt_boot/aee/mrdump_dummy.c

@@ -0,0 +1,107 @@
+/* Copyright Statement:
+*
+* This software/firmware and related documentation ("MediaTek Software") are
+* protected under relevant copyright laws. The information contained herein
+* is confidential and proprietary to MediaTek Inc. and/or its licensors.
+* Without the prior written permission of MediaTek inc. and/or its licensors,
+* any reproduction, modification, use or disclosure of MediaTek Software,
+* and information contained herein, in whole or in part, shall be strictly prohibited.
+*/
+/* MediaTek Inc. (C) 2016. All rights reserved.
+*
+* BY OPENING THIS FILE, RECEIVER HEREBY UNEQUIVOCALLY ACKNOWLEDGES AND AGREES
+* THAT THE SOFTWARE/FIRMWARE AND ITS DOCUMENTATIONS ("MEDIATEK SOFTWARE")
+* RECEIVED FROM MEDIATEK AND/OR ITS REPRESENTATIVES ARE PROVIDED TO RECEIVER ON
+* AN "AS-IS" BASIS ONLY. MEDIATEK EXPRESSLY DISCLAIMS ANY AND ALL WARRANTIES,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED WARRANTIES OF
+* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE OR NONINFRINGEMENT.
+* NEITHER DOES MEDIATEK PROVIDE ANY WARRANTY WHATSOEVER WITH RESPECT TO THE
+* SOFTWARE OF ANY THIRD PARTY WHICH MAY BE USED BY, INCORPORATED IN, OR
+* SUPPLIED WITH THE MEDIATEK SOFTWARE, AND RECEIVER AGREES TO LOOK ONLY TO SUCH
+* THIRD PARTY FOR ANY WARRANTY CLAIM RELATING THERETO. RECEIVER EXPRESSLY ACKNOWLEDGES
+* THAT IT IS RECEIVER'S SOLE RESPONSIBILITY TO OBTAIN FROM ANY THIRD PARTY ALL PROPER LICENSES
+* CONTAINED IN MEDIATEK SOFTWARE. MEDIATEK SHALL ALSO NOT BE RESPONSIBLE FOR ANY MEDIATEK
+* SOFTWARE RELEASES MADE TO RECEIVER'S SPECIFICATION OR TO CONFORM TO A PARTICULAR
+* STANDARD OR OPEN FORUM. RECEIVER'S SOLE AND EXCLUSIVE REMEDY AND MEDIATEK'S ENTIRE AND
+* CUMULATIVE LIABILITY WITH RESPECT TO THE MEDIATEK SOFTWARE RELEASED HEREUNDER WILL BE,
+* AT MEDIATEK'S OPTION, TO REVISE OR REPLACE THE MEDIATEK SOFTWARE AT ISSUE,
+* OR REFUND ANY SOFTWARE LICENSE FEES OR SERVICE CHARGE PAID BY RECEIVER TO
+* MEDIATEK FOR SUCH MEDIATEK SOFTWARE AT ISSUE.
+*/
+
+#include <debug.h>
+#include <dev/mrdump.h>
+#include <memory_layout.h>
+#include <platform/boot_mode.h>
+
+int mrdump_detection(void) __attribute__((weak));
+int mrdump_detection(void)
+{
+	return 0;
+}
+
+void mrdump_reserve_memory(void) __attribute__((weak));
+void mrdump_reserve_memory(void)
+{
+#ifdef PL_DRAMBUF_BASE
+	if (mblock_query_reserved(&g_boot_arg->mblock_info,
+				  "pl-drambuf", 0)) {
+		if (mblock_create(&g_boot_arg->mblock_info,
+				  &g_boot_arg->orig_dram_info,
+				  PL_DRAMBUF_BASE, PL_DRAMBUF_MAX_SIZE)) {
+			dprintf(CRITICAL, "%s: free PL_DRAMBUF_ARG failed\n", __func__);
+			assert(0);
+		}
+	}
+#endif /* end of PL_DRAMBUF_BASE */
+#ifdef PL_BOOTTAGS_BASE
+	if (mblock_query_reserved(&g_boot_arg->mblock_info,
+				  "pl-boottag", 0)) {
+		if (mblock_create(&g_boot_arg->mblock_info,
+				  &g_boot_arg->orig_dram_info,
+				  PL_BOOTTAGS_BASE, PL_BOOTTAGS_MAX_SIZE)) {
+			dprintf(CRITICAL, "%s: free PL_BOOT_ARG failed\n", __func__);
+			assert(0);
+		}
+	}
+#endif /* end of PL_BOOTTAGS_BASE */
+#ifdef PL_BOOTARG_BASE
+	if (mblock_query_reserved(&g_boot_arg->mblock_info,
+				  "pl-bootarg", 0)) {
+		if (mblock_create(&g_boot_arg->mblock_info,
+				  &g_boot_arg->orig_dram_info,
+				  PL_BOOTARG_BASE, PL_BOOTARG_MAX_SIZE)) {
+			dprintf(CRITICAL, "%s: free PL_BOOTARG_BASE failed\n", __func__);
+			assert(0);
+		}
+	}
+#endif /* end of PL_BOOTARG_BASE */
+}
+
+int mrdump_run2(void) __attribute__((weak));
+int mrdump_run2(void)
+{
+	return 0;
+}
+
+void mrdump_reboot(void) __attribute__((weak));
+void mrdump_reboot(void)
+{
+}
+
+int sLOG(char *fmt, ...) __attribute__((weak));
+int sLOG(char *fmt, ...)
+{
+	return 0;
+}
+
+void mrdump_init(void *fdt) __attribute__((weak));
+void mrdump_init(void *fdt)
+{
+}
+
+int mrdump_check_enable(void) __attribute__((weak));
+int mrdump_check_enable(void)
+{
+	return MRDUMP_ALWAYS_DISABLE;
+}

+ 478 - 0
app/mt_boot/aee/mrdump_elf.c

@@ -0,0 +1,478 @@
+/* Copyright Statement:
+*
+* This software/firmware and related documentation ("MediaTek Software") are
+* protected under relevant copyright laws. The information contained herein
+* is confidential and proprietary to MediaTek Inc. and/or its licensors.
+* Without the prior written permission of MediaTek inc. and/or its licensors,
+* any reproduction, modification, use or disclosure of MediaTek Software,
+* and information contained herein, in whole or in part, shall be strictly prohibited.
+*/
+/* MediaTek Inc. (C) 2016. All rights reserved.
+*
+* BY OPENING THIS FILE, RECEIVER HEREBY UNEQUIVOCALLY ACKNOWLEDGES AND AGREES
+* THAT THE SOFTWARE/FIRMWARE AND ITS DOCUMENTATIONS ("MEDIATEK SOFTWARE")
+* RECEIVED FROM MEDIATEK AND/OR ITS REPRESENTATIVES ARE PROVIDED TO RECEIVER ON
+* AN "AS-IS" BASIS ONLY. MEDIATEK EXPRESSLY DISCLAIMS ANY AND ALL WARRANTIES,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED WARRANTIES OF
+* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE OR NONINFRINGEMENT.
+* NEITHER DOES MEDIATEK PROVIDE ANY WARRANTY WHATSOEVER WITH RESPECT TO THE
+* SOFTWARE OF ANY THIRD PARTY WHICH MAY BE USED BY, INCORPORATED IN, OR
+* SUPPLIED WITH THE MEDIATEK SOFTWARE, AND RECEIVER AGREES TO LOOK ONLY TO SUCH
+* THIRD PARTY FOR ANY WARRANTY CLAIM RELATING THERETO. RECEIVER EXPRESSLY ACKNOWLEDGES
+* THAT IT IS RECEIVER'S SOLE RESPONSIBILITY TO OBTAIN FROM ANY THIRD PARTY ALL PROPER LICENSES
+* CONTAINED IN MEDIATEK SOFTWARE. MEDIATEK SHALL ALSO NOT BE RESPONSIBLE FOR ANY MEDIATEK
+* SOFTWARE RELEASES MADE TO RECEIVER'S SPECIFICATION OR TO CONFORM TO A PARTICULAR
+* STANDARD OR OPEN FORUM. RECEIVER'S SOLE AND EXCLUSIVE REMEDY AND MEDIATEK'S ENTIRE AND
+* CUMULATIVE LIABILITY WITH RESPECT TO THE MEDIATEK SOFTWARE RELEASED HEREUNDER WILL BE,
+* AT MEDIATEK'S OPTION, TO REVISE OR REPLACE THE MEDIATEK SOFTWARE AT ISSUE,
+* OR REFUND ANY SOFTWARE LICENSE FEES OR SERVICE CHARGE PAID BY RECEIVER TO
+* MEDIATEK FOR SUCH MEDIATEK SOFTWARE AT ISSUE.
+*/
+
+#include <assert.h>
+#include <malloc.h>
+#include <string.h>
+#include <printf.h>
+#include "aee.h"
+#include "mrdump_private.h"
+#include "mrdump_elf.h"
+
+#define mrdump_elf_setup_elfhdr(elfp, machid, elfhdr_t, elfphdr_t, phdrcount)	\
+	elfp->e_type = ET_CORE;						\
+	elfp->e_machine = machid;					\
+	elfp->e_version = EV_CURRENT;					\
+	elfp->e_entry = 0;						\
+	elfp->e_phoff = sizeof(elfhdr_t);				\
+	elfp->e_shoff = 0;						\
+	elfp->e_flags = ELF_CORE_EFLAGS;				\
+	elfp->e_ehsize = sizeof(elfhdr_t);				\
+	elfp->e_phentsize = sizeof(elfphdr_t);				\
+	elfp->e_phnum = phdrcount;					\
+	elfp->e_shentsize = 0;						\
+	elfp->e_shnum = 0;						\
+	elfp->e_shstrndx = 0;						\
+
+static inline void mrdump_elf_setup_eident(unsigned char e_ident[EI_NIDENT], unsigned char elfclasz)
+{
+	memcpy(e_ident, ELFMAG, SELFMAG);
+	e_ident[EI_CLASS] = elfclasz;
+	e_ident[EI_DATA] = ELFDATA2LSB;
+	e_ident[EI_VERSION] = EV_CURRENT;
+	e_ident[EI_OSABI] = ELFOSABI_NONE;
+	memset(e_ident+EI_PAD, 0, EI_NIDENT-EI_PAD);
+}
+
+static uint32_t roundup(uint32_t x, uint32_t y)
+{
+	return ((x + y - 1) / y) * y;
+}
+
+/* An ELF note in memory */
+struct memelfnote {
+	const char *name;
+	int type;
+	unsigned int datasz;
+	void *data;
+};
+
+static int notesize(struct memelfnote *en)
+{
+	int sz;
+
+	sz = sizeof(struct elf32_note);
+	sz += roundup((strlen(en->name) + 1), 4);
+	sz += roundup(en->datasz, 4);
+
+	return sz;
+}
+
+static uint8_t *storenote(struct memelfnote *men, uint8_t *bufp)
+{
+	struct elf32_note en;
+	en.n_namesz = strlen(men->name) + 1;
+	en.n_descsz = men->datasz;
+	en.n_type = men->type;
+
+	memcpy(bufp, &en, sizeof(en));
+	bufp += sizeof(en);
+
+	memcpy(bufp, men->name, en.n_namesz);
+	bufp += en.n_namesz;
+
+	bufp = (uint8_t*) roundup((unsigned long)bufp, 4);
+	memcpy(bufp, men->data, men->datasz);
+	bufp += men->datasz;
+
+	bufp = (uint8_t*) roundup((unsigned long)bufp, 4);
+	return bufp;
+}
+
+static uint8_t *mrdump_core32_write_cpu_note(const struct mrdump_control_block *mrdump_cb,
+					     unsigned int cpu, struct elf32_phdr *nhdr,
+					     uint8_t *bufp)
+{
+	if (cpu >= MRDUMP_CPU_MAX) {
+		/* cpu value is not correct, ignore it */
+		return bufp;
+	}
+
+	struct memelfnote notes;
+	struct elf32_arm_prstatus prstatus;
+	char cpustr[16];
+
+	memset(&prstatus, 0, sizeof(struct elf32_arm_prstatus));
+
+	ASSERT(snprintf(cpustr, sizeof(cpustr), "CPU%d", cpu) > 0);
+	/* set up the process status */
+	notes.name = cpustr;
+	notes.type = NT_PRSTATUS;
+	notes.datasz = sizeof(struct elf32_arm_prstatus);
+	notes.data = &prstatus;
+
+	prstatus.pr_pid = cpu + 1;
+	memcpy(&prstatus.pr_reg, (unsigned long*)&mrdump_cb->crash_record.cpu_regs[cpu].arm32_regs,
+	       sizeof(elf_arm_gregset_t));
+
+	nhdr->p_filesz += notesize(&notes);
+	return storenote(&notes, bufp);
+}
+
+static uint8_t *mrdump_core32_write_machdesc(const struct mrdump_control_block *mrdump_cb, struct elf32_phdr *nhdr, uint8_t *bufp)
+{
+	struct memelfnote notes;
+	struct elf_mrdump_machdesc machdesc;
+	const struct mrdump_machdesc *kparams = &mrdump_cb->machdesc;
+
+	memset(&machdesc, 0, sizeof(struct elf_mrdump_machdesc));
+
+	notes.name = "MRDUMP01";
+	notes.type = NT_MRDUMP_MACHDESC;
+	notes.datasz = sizeof(struct elf_mrdump_machdesc);
+	notes.data = &machdesc;
+
+	machdesc.flags = MRDUMP_TYPE_FULL_MEMORY;
+	machdesc.nr_cpus = kparams->nr_cpus;
+	machdesc.phys_offset = kparams->phys_offset;
+	machdesc.page_offset = kparams->page_offset;
+	machdesc.high_memory = kparams->high_memory;
+	machdesc.kimage_vaddr = kparams->kimage_vaddr;
+	machdesc.modules_start = kparams->modules_start;
+	machdesc.modules_end = kparams->modules_end;
+	machdesc.vmalloc_start = kparams->vmalloc_start;
+	machdesc.vmalloc_end = kparams->vmalloc_end;
+	machdesc.master_page_table = kparams->master_page_table;
+
+	nhdr->p_filesz += notesize(&notes);
+	return storenote(&notes, bufp);
+}
+
+static uint8_t *mrdump_core32_write_cb(const struct mrdump_control_block *mrdump_cb, struct elf32_phdr *nhdr, uint8_t *bufp)
+{
+	struct memelfnote notes;
+	uint64_t mrdump_cb_paddr = (uint64_t)(uintptr_t)mrdump_cb;
+
+	notes.name = MRDUMP_GO_DUMP;
+	notes.type = NT_MRDUMP_CBLOCK;
+	notes.datasz = sizeof(mrdump_cb_paddr);
+	notes.data = &mrdump_cb_paddr;
+
+	nhdr->p_filesz += notesize(&notes);
+	return storenote(&notes, bufp);
+}
+
+static void mrdump_core32_header_init(const struct mrdump_control_block *mrdump_cb, const struct kzip_addlist *memlist)
+{
+	struct elf32_phdr *nhdr, *phdr;
+	struct elf32_hdr *elf;
+	off_t offset = 0;
+	const struct mrdump_machdesc *kparams = &mrdump_cb->machdesc;
+
+	uint8_t *bufp = (uint8_t *)(uintptr_t)memlist[0].address;
+
+	elf = (struct elf32_hdr *) bufp;
+	bufp += sizeof(struct elf32_hdr);
+	offset += sizeof(struct elf32_hdr);
+
+	nhdr = (struct elf32_phdr *) bufp;
+	bufp += sizeof(struct elf32_phdr);
+	offset += sizeof(struct elf32_phdr);
+	memset(nhdr, 0, sizeof(struct elf32_phdr));
+	nhdr->p_type = PT_NOTE;
+
+	unsigned long long foffset = MRDUMP_CORE_HEADER_SIZE;
+	int i;
+	for (i = 1; memlist[i].address != 0;i++) {
+		phdr = (struct elf32_phdr *) bufp;
+		bufp += sizeof(struct elf32_phdr);
+		offset += sizeof(struct elf32_phdr);
+
+		phdr->p_type    = PT_LOAD;
+		phdr->p_flags   = PF_R|PF_W|PF_X;
+		phdr->p_offset  = foffset;
+		phdr->p_vaddr   = 0;
+		phdr->p_paddr   = memlist[i].address;
+		phdr->p_filesz  = memlist[i].size;
+		phdr->p_memsz   = memlist[i].size;
+		phdr->p_align   = 0;
+
+		foffset += phdr->p_filesz;
+	}
+
+	mrdump_elf_setup_eident(elf->e_ident, ELFCLASS32);
+	mrdump_elf_setup_elfhdr(elf, EM_ARM, struct elf32_hdr, struct elf32_phdr, i);
+
+	nhdr->p_offset = offset;
+
+	/* NT_PRPSINFO */
+	struct elf32_prpsinfo prpsinfo;
+	struct memelfnote notes;
+	/* set up the process info */
+	notes.name = CORE_STR;
+	notes.type = NT_PRPSINFO;
+	notes.datasz = sizeof(struct elf32_prpsinfo);
+	notes.data = &prpsinfo;
+
+	memset(&prpsinfo, 0, sizeof(struct elf32_prpsinfo));
+	prpsinfo.pr_state = 0;
+	prpsinfo.pr_sname = 'R';
+	prpsinfo.pr_zomb = 0;
+	prpsinfo.pr_gid = prpsinfo.pr_uid = mrdump_cb->crash_record.fault_cpu + 1;
+	strlcpy(prpsinfo.pr_fname, "vmlinux", sizeof(prpsinfo.pr_fname));
+	strlcpy(prpsinfo.pr_psargs, "vmlinux", ELF_PRARGSZ);
+
+	nhdr->p_filesz += notesize(&notes);
+	bufp = storenote(&notes, bufp);
+
+	bufp = mrdump_core32_write_machdesc(mrdump_cb, nhdr, bufp);
+
+	/* Store pre-cpu backtrace */
+	bufp = mrdump_core32_write_cpu_note(mrdump_cb, mrdump_cb->crash_record.fault_cpu, nhdr, bufp);
+	for (unsigned int cpu = 0; cpu < kparams->nr_cpus; cpu++) {
+		if (cpu != mrdump_cb->crash_record.fault_cpu) {
+			bufp = mrdump_core32_write_cpu_note(mrdump_cb, cpu, nhdr, bufp);
+		}
+	}
+
+	/* store mrdump control block */
+	bufp = mrdump_core32_write_cb(mrdump_cb, nhdr, bufp);
+}
+
+static int notesize64(struct memelfnote *en)
+{
+	int sz;
+
+	sz = sizeof(struct elf64_note);
+	sz += roundup((strlen(en->name) + 1), 4);
+	sz += roundup(en->datasz, 4);
+
+	return sz;
+}
+
+static uint8_t *storenote64(struct memelfnote *men, uint8_t *bufp)
+{
+	struct elf64_note en;
+	en.n_namesz = strlen(men->name) + 1;
+	en.n_descsz = men->datasz;
+	en.n_type = men->type;
+
+	memcpy(bufp, &en, sizeof(en));
+	bufp += sizeof(en);
+
+	memcpy(bufp, men->name, en.n_namesz);
+	bufp += en.n_namesz;
+
+	bufp = (uint8_t*) roundup((unsigned long)bufp, 4);
+	memcpy(bufp, men->data, men->datasz);
+	bufp += men->datasz;
+
+	bufp = (uint8_t*) roundup((unsigned long)bufp, 4);
+	return bufp;
+}
+
+static uint8_t *mrdump_core64_write_cpu_note(const struct mrdump_control_block *mrdump_cb,
+					     unsigned int cpu, struct elf64_phdr *nhdr, uint8_t *bufp)
+{
+	if (cpu >= MRDUMP_CPU_MAX) {
+		/* cpu value is not correct, ignore it */
+		return bufp;
+	}
+
+	struct memelfnote notes;
+	struct elf_arm64_prstatus64 prstatus;
+	char cpustr[16];
+
+	memset(&prstatus, 0, sizeof(struct elf_arm64_prstatus64));
+	ASSERT(snprintf(cpustr, sizeof(cpustr), "CPU%d", cpu) > 0);
+
+	/* set up the process status */
+	notes.name = cpustr;
+	notes.type = NT_PRSTATUS;
+	notes.datasz = sizeof(struct elf_arm64_prstatus64);
+	notes.data = &prstatus;
+
+	prstatus.pr_pid = cpu + 1;
+	memcpy(&prstatus.pr_reg, &mrdump_cb->crash_record.cpu_regs[cpu].arm64_regs, sizeof(elf_arm64_gregset_t));
+
+	nhdr->p_filesz += notesize64(&notes);
+	return storenote64(&notes, bufp);
+}
+
+static uint8_t *mrdump_core64_write_machdesc(const struct mrdump_control_block *mrdump_cb, struct elf64_phdr *nhdr, uint8_t *bufp)
+{
+	struct memelfnote notes;
+	struct elf_mrdump_machdesc machdesc;
+	const struct mrdump_machdesc *kparams = &mrdump_cb->machdesc;
+
+	memset(&machdesc, 0, sizeof(struct elf_mrdump_machdesc));
+
+	notes.name = "MRDUMP01";
+	notes.type = NT_MRDUMP_MACHDESC;
+	notes.datasz = sizeof(struct elf_mrdump_machdesc);
+	notes.data = &machdesc;
+
+	machdesc.flags = MRDUMP_TYPE_FULL_MEMORY;
+	machdesc.nr_cpus = kparams->nr_cpus;
+	machdesc.phys_offset = kparams->phys_offset;
+	machdesc.page_offset = kparams->page_offset;
+	machdesc.high_memory = kparams->high_memory;
+	machdesc.kimage_vaddr = kparams->kimage_vaddr;
+	machdesc.modules_start = kparams->modules_start;
+	machdesc.modules_end = kparams->modules_end;
+	machdesc.vmalloc_start = kparams->vmalloc_start;
+	machdesc.vmalloc_end = kparams->vmalloc_end;
+	machdesc.master_page_table = kparams->master_page_table;
+
+	nhdr->p_filesz += notesize64(&notes);
+	return storenote64(&notes, bufp);
+}
+
+static uint8_t *mrdump_core64_write_vmcoreinfo(const struct mrdump_control_block *mrdump_cb, struct elf64_phdr *nhdr, uint8_t *bufp)
+{
+	struct memelfnote notes;
+	const struct mrdump_machdesc *kparams = &mrdump_cb->machdesc;
+	char vmcoreinfo[512];
+
+	memset(vmcoreinfo, 0, sizeof(vmcoreinfo));
+
+	notes.name = "VMCOREINFO";
+	notes.type = 0;
+	notes.datasz = 0;
+	notes.data = &vmcoreinfo;
+	ASSERT(snprintf(vmcoreinfo, sizeof(vmcoreinfo),
+			"PAGESIZE=4096\n"
+			"NUMBER(kimage_voffset)=0x%llx\n"
+			"SYMBOL(_stext)=0x%llx\n"
+			"NUMBER(VA_BITS)=%d\n"
+			"NUMBER(PHYS_OFFSET)=0x%llx\n",
+			(uint64_t)kparams->kimage_voffset,
+			(uint64_t)kparams->kimage_stext_real,
+			39,
+			(uint64_t)kparams->phys_offset) > 0);
+	notes.datasz = strlen(vmcoreinfo);
+
+	nhdr->p_filesz += notesize64(&notes);
+	return storenote64(&notes, bufp);
+}
+
+static uint8_t *mrdump_core64_write_cb(const struct mrdump_control_block *mrdump_cb, struct elf64_phdr *nhdr, uint8_t *bufp)
+{
+	struct memelfnote notes;
+	uint64_t mrdump_cb_paddr = (uint64_t)(uintptr_t)mrdump_cb;
+
+	notes.name = MRDUMP_GO_DUMP;
+	notes.type = NT_MRDUMP_CBLOCK;
+	notes.datasz = sizeof(mrdump_cb_paddr);
+	notes.data = &mrdump_cb_paddr;
+
+	nhdr->p_filesz += notesize64(&notes);
+	return storenote64(&notes, bufp);
+}
+
+static void mrdump_core64_header_init(const struct mrdump_control_block *mrdump_cb, const struct kzip_addlist *memlist)
+{
+	struct elf64_phdr *nhdr, *phdr;
+	struct elf64_hdr *elf;
+	off_t offset = 0;
+	const struct mrdump_machdesc *kparams = &mrdump_cb->machdesc;
+
+	uint8_t *bufp = (uint8_t *)(uintptr_t)memlist[0].address;
+
+	elf = (struct elf64_hdr *) bufp;
+	bufp += sizeof(struct elf64_hdr);
+	offset += sizeof(struct elf64_hdr);
+
+	nhdr = (struct elf64_phdr *) bufp;
+	bufp += sizeof(struct elf64_phdr);
+	offset += sizeof(struct elf64_phdr);
+	memset(nhdr, 0, sizeof(struct elf64_phdr));
+	nhdr->p_type = PT_NOTE;
+
+	unsigned long long foffset = MRDUMP_CORE_HEADER_SIZE;
+	int i;
+	for (i = 1; memlist[i].address != 0;i++) {
+		phdr = (struct elf64_phdr *) bufp;
+		bufp += sizeof(struct elf64_phdr);
+		offset += sizeof(struct elf64_phdr);
+
+		phdr->p_type    = PT_LOAD;
+		phdr->p_flags   = PF_R|PF_W|PF_X;
+		phdr->p_offset  = foffset;
+		phdr->p_vaddr   = 0;
+		phdr->p_paddr   = memlist[i].address;
+		phdr->p_filesz  = memlist[i].size;
+		phdr->p_memsz   = memlist[i].size;
+		phdr->p_align   = 0;
+
+		foffset += phdr->p_filesz;
+	}
+
+	mrdump_elf_setup_eident(elf->e_ident, ELFCLASS64);
+	mrdump_elf_setup_elfhdr(elf, EM_AARCH64, struct elf64_hdr, struct elf64_phdr, i);
+
+	nhdr->p_offset = offset;
+
+	/* NT_PRPSINFO */
+	struct elf_prpsinfo64 prpsinfo;
+	struct memelfnote notes;
+	/* set up the process info */
+	notes.name = CORE_STR;
+	notes.type = NT_PRPSINFO;
+	notes.datasz = sizeof(struct elf_prpsinfo64);
+	notes.data = &prpsinfo;
+
+	memset(&prpsinfo, 0, sizeof(struct elf_prpsinfo64));
+	prpsinfo.pr_state = 0;
+	prpsinfo.pr_sname = 'R';
+	prpsinfo.pr_zomb = 0;
+	prpsinfo.pr_gid = prpsinfo.pr_uid = mrdump_cb->crash_record.fault_cpu + 1;
+	strlcpy(prpsinfo.pr_fname, "vmlinux", sizeof(prpsinfo.pr_fname));
+	strlcpy(prpsinfo.pr_psargs, "vmlinux", ELF_PRARGSZ);
+
+	nhdr->p_filesz += notesize64(&notes);
+	bufp = storenote64(&notes, bufp);
+
+	bufp = mrdump_core64_write_machdesc(mrdump_cb, nhdr, bufp);
+	bufp = mrdump_core64_write_vmcoreinfo(mrdump_cb, nhdr, bufp);
+
+	/* Store pre-cpu backtrace */
+	bufp = mrdump_core64_write_cpu_note(mrdump_cb, mrdump_cb->crash_record.fault_cpu, nhdr, bufp);
+	for (unsigned int cpu = 0; cpu < kparams->nr_cpus; cpu++) {
+		if (cpu != mrdump_cb->crash_record.fault_cpu) {
+			bufp = mrdump_core64_write_cpu_note(mrdump_cb, cpu, nhdr, bufp);
+		}
+	}
+
+	/* store mrdump control block */
+	bufp = mrdump_core64_write_cb(mrdump_cb, nhdr, bufp);
+}
+
+void mrdump_core_header_init(const struct mrdump_control_block *kparams, const struct kzip_addlist *memlist)
+{
+	if (kparams->machdesc.page_offset <= 0xffffffffULL) {
+		voprintf_info("32b kernel detected\n");
+		mrdump_core32_header_init(kparams, memlist);
+	} else {
+		voprintf_info("64b kernel detected\n");
+		mrdump_core64_header_init(kparams, memlist);
+	}
+}

+ 298 - 0
app/mt_boot/aee/mrdump_elf.h

@@ -0,0 +1,298 @@
+/* Copyright Statement:
+*
+* This software/firmware and related documentation ("MediaTek Software") are
+* protected under relevant copyright laws. The information contained herein
+* is confidential and proprietary to MediaTek Inc. and/or its licensors.
+* Without the prior written permission of MediaTek inc. and/or its licensors,
+* any reproduction, modification, use or disclosure of MediaTek Software,
+* and information contained herein, in whole or in part, shall be strictly prohibited.
+*/
+/* MediaTek Inc. (C) 2016. All rights reserved.
+*
+* BY OPENING THIS FILE, RECEIVER HEREBY UNEQUIVOCALLY ACKNOWLEDGES AND AGREES
+* THAT THE SOFTWARE/FIRMWARE AND ITS DOCUMENTATIONS ("MEDIATEK SOFTWARE")
+* RECEIVED FROM MEDIATEK AND/OR ITS REPRESENTATIVES ARE PROVIDED TO RECEIVER ON
+* AN "AS-IS" BASIS ONLY. MEDIATEK EXPRESSLY DISCLAIMS ANY AND ALL WARRANTIES,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED WARRANTIES OF
+* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE OR NONINFRINGEMENT.
+* NEITHER DOES MEDIATEK PROVIDE ANY WARRANTY WHATSOEVER WITH RESPECT TO THE
+* SOFTWARE OF ANY THIRD PARTY WHICH MAY BE USED BY, INCORPORATED IN, OR
+* SUPPLIED WITH THE MEDIATEK SOFTWARE, AND RECEIVER AGREES TO LOOK ONLY TO SUCH
+* THIRD PARTY FOR ANY WARRANTY CLAIM RELATING THERETO. RECEIVER EXPRESSLY ACKNOWLEDGES
+* THAT IT IS RECEIVER'S SOLE RESPONSIBILITY TO OBTAIN FROM ANY THIRD PARTY ALL PROPER LICENSES
+* CONTAINED IN MEDIATEK SOFTWARE. MEDIATEK SHALL ALSO NOT BE RESPONSIBLE FOR ANY MEDIATEK
+* SOFTWARE RELEASES MADE TO RECEIVER'S SPECIFICATION OR TO CONFORM TO A PARTICULAR
+* STANDARD OR OPEN FORUM. RECEIVER'S SOLE AND EXCLUSIVE REMEDY AND MEDIATEK'S ENTIRE AND
+* CUMULATIVE LIABILITY WITH RESPECT TO THE MEDIATEK SOFTWARE RELEASED HEREUNDER WILL BE,
+* AT MEDIATEK'S OPTION, TO REVISE OR REPLACE THE MEDIATEK SOFTWARE AT ISSUE,
+* OR REFUND ANY SOFTWARE LICENSE FEES OR SERVICE CHARGE PAID BY RECEIVER TO
+* MEDIATEK FOR SUCH MEDIATEK SOFTWARE AT ISSUE.
+*/
+
+#if !defined(__MRDUMP_ELF_H__)
+#define __MRDUMP_ELF_H__
+
+#include <stdint.h>
+
+#define ELFMAG      "\177ELF"
+#define SELFMAG     4
+
+#define CORE_STR "CORE"
+
+#ifndef ELF_CORE_EFLAGS
+#define ELF_CORE_EFLAGS 0
+#endif
+
+#define EI_NIDENT   16
+
+#define EI_CLASS    4
+#define EI_DATA     5
+#define EI_VERSION  6
+#define EI_OSABI    7
+#define EI_PAD      8
+
+#define EM_ARM 40
+#define EM_AARCH64 183
+
+#define ET_CORE 4
+
+#define PT_LOAD 1
+#define PT_NOTE 4
+
+#define ELFCLASS32 1
+#define ELFCLASS64 2
+
+#define NT_PRSTATUS 1
+#define NT_PRFPREG 2
+#define NT_PRPSINFO 3
+/* MRDUMP support note type */
+#define NT_MRDUMP_MACHDESC 0xAEE0
+#define NT_MRDUMP_CBLOCK 0xBEEF
+
+
+#define PF_R 0x4
+#define PF_W 0x2
+#define PF_X 0x1
+
+#define ELFOSABI_NONE 0
+
+#define EV_CURRENT 1
+
+#define ELFDATA2LSB 1
+
+#define ELF_PRARGSZ 80
+
+#define MRDUMP_TYPE_FULL_MEMORY 0
+#define MRDUMP_TYPE_KERNEL_1 1
+#define MRDUMP_TYPE_KERNEL_2 2
+
+#define MRDUMP_TYPE_MASK 0x3
+
+#define NT_IPANIC_MISC 4095
+
+typedef uint32_t Elf32_Addr;
+typedef uint16_t Elf32_Half;
+typedef uint32_t Elf32_Off;
+typedef int32_t Elf32_Sword;
+typedef uint32_t Elf32_Word;
+
+typedef uint64_t Elf64_Addr;
+typedef uint16_t Elf64_Half;
+typedef uint64_t Elf64_Off;
+typedef uint32_t Elf64_Word;
+typedef uint64_t Elf64_Xword;
+
+struct elf_siginfo {
+	int si_signo;
+	int si_code;
+	int si_errno;
+};
+
+struct __attribute__((__packed__)) elf_mrdump_machdesc {
+	uint32_t flags;
+	uint32_t nr_cpus;
+
+	uint64_t phys_offset;
+	uint64_t total_memory;
+
+	uint64_t page_offset;
+	uint64_t high_memory;
+
+	uint64_t kimage_vaddr;
+
+	uint64_t modules_start;
+	uint64_t modules_end;
+
+	uint64_t vmalloc_start;
+	uint64_t vmalloc_end;
+
+	uint64_t master_page_table;
+
+	uint64_t dfdmem_pa;
+};
+
+#define ELF_ARM_NGREGS 18
+typedef uint32_t elf_arm_gregset_t[ELF_ARM_NGREGS];
+
+typedef struct elf32_hdr {
+	unsigned char e_ident[EI_NIDENT];
+	Elf32_Half e_type;
+	Elf32_Half e_machine;
+	Elf32_Word e_version;
+	Elf32_Addr e_entry;
+	Elf32_Off e_phoff;
+	Elf32_Off e_shoff;
+	Elf32_Word e_flags;
+	Elf32_Half e_ehsize;
+	Elf32_Half e_phentsize;
+	Elf32_Half e_phnum;
+	Elf32_Half e_shentsize;
+	Elf32_Half e_shnum;
+	Elf32_Half e_shstrndx;
+} Elf64_Ehdr;
+
+typedef struct elf32_phdr {
+	Elf32_Word p_type;
+	Elf32_Off p_offset;
+	Elf32_Addr p_vaddr;
+	Elf32_Addr p_paddr;
+	Elf32_Word p_filesz;
+	Elf32_Word p_memsz;
+	Elf32_Word p_flags;
+	Elf32_Word p_align;
+} Elf32_Phdr;
+
+typedef struct elf32_note {
+	Elf32_Word   n_namesz;       /* Name size */
+	Elf32_Word   n_descsz;       /* Content size */
+	Elf32_Word   n_type;         /* Content type */
+} Elf_Nhdr;
+
+struct elf32_timeval {
+	int32_t tv_sec;
+	int32_t tv_usec;
+};
+
+struct elf32_arm_prstatus {
+	struct elf_siginfo pr_info;
+	short pr_cursig;
+	unsigned long pr_sigpend;
+	unsigned long pr_sighold;
+
+	int32_t pr_pid;
+	int32_t pr_ppid;
+	int32_t pr_pgrp;
+
+	int32_t pr_sid;
+	struct elf32_timeval pr_utime;
+	struct elf32_timeval pr_stime;
+	struct elf32_timeval pr_cutime;
+	struct elf32_timeval pr_cstime;
+
+	elf_arm_gregset_t pr_reg;
+
+	int pr_fpvalid;
+};
+
+struct elf32_prpsinfo {
+	char pr_state;
+	char pr_sname;
+	char pr_zomb;
+	char pr_nice;
+	unsigned long pr_flag;
+
+	uint16_t pr_uid;
+	uint16_t pr_gid;
+
+	int32_t pr_pid;
+	int32_t pr_ppid;
+	int32_t pr_pgrp;
+	int32_t pr_sid;
+
+	char pr_fname[16];
+	char pr_psargs[ELF_PRARGSZ];
+};
+
+#define ELF_ARM64_NGREGS 34
+typedef uint64_t elf_arm64_gregset_t[ELF_ARM64_NGREGS];
+
+typedef struct elf64_hdr {
+	unsigned char e_ident[EI_NIDENT];
+	Elf64_Half e_type;
+	Elf64_Half e_machine;
+	Elf64_Word e_version;
+	Elf64_Addr e_entry;
+	Elf64_Off e_phoff;
+	Elf64_Off e_shoff;
+	Elf64_Word e_flags;
+	Elf64_Half e_ehsize;
+	Elf64_Half e_phentsize;
+	Elf64_Half e_phnum;
+	Elf64_Half e_shentsize;
+	Elf64_Half e_shnum;
+	Elf64_Half e_shstrndx;
+} Elf64_ehdr;
+
+typedef struct elf64_phdr {
+	Elf64_Word p_type;
+	Elf64_Word p_flags;
+	Elf64_Off p_offset;
+	Elf64_Addr p_vaddr;
+	Elf64_Addr p_paddr;
+	Elf64_Xword p_filesz;
+	Elf64_Xword p_memsz;
+	Elf64_Xword p_align;
+} Elf64_phdr;
+
+typedef struct elf64_note {
+	Elf64_Word    n_namesz;   /* Name size */
+	Elf64_Word    n_descsz;   /* Content size */
+	Elf64_Word    n_type;     /* Content type */
+} Elf64_nhdr;
+
+struct elf_timeval64 {
+	int64_t tv_sec;
+	int64_t tv_usec;
+};
+
+struct elf_arm64_prstatus64 {
+	struct elf_siginfo pr_info;
+	short pr_cursig;
+	uint64_t pr_sigpend;
+	uint64_t pr_sighold;
+
+	int32_t pr_pid;
+	int32_t pr_ppid;
+	int32_t pr_pgrp;
+
+	int32_t pr_sid;
+	struct elf_timeval64 pr_utime;
+	struct elf_timeval64 pr_stime;
+	struct elf_timeval64 pr_cutime;
+	struct elf_timeval64 pr_cstime;
+
+	elf_arm64_gregset_t pr_reg;
+
+	int pr_fpvalid;
+};
+
+struct elf_prpsinfo64 {
+	char pr_state;
+	char pr_sname;
+	char pr_zomb;
+	char pr_nice;
+	uint64_t pr_flag;
+
+	uint32_t pr_uid;
+	uint32_t pr_gid;
+
+	int32_t pr_pid;
+	int32_t pr_ppid;
+	int32_t pr_pgrp;
+	int32_t pr_sid;
+
+	char pr_fname[16];
+	char pr_psargs[ELF_PRARGSZ];
+};
+
+#endif /* __MRDUMP_ELF_H__ */

+ 175 - 0
app/mt_boot/aee/mrdump_key_setup.c

@@ -0,0 +1,175 @@
+/*
+ * Copyright (c) 2020 MediaTek Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files
+ * (the "Software"), to deal in the Software without restriction,
+ * including without limitation the rights to use, copy, modify, merge,
+ * publish, distribute, sublicense, and/or sell copies of the Software,
+ * and to permit persons to whom the Software is furnished to do so,
+ * subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+ * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#ifndef CFG_MTK_WDT_COMMON
+
+#include <printf.h>
+
+void mrdump_key_secure_enable(void)
+{
+	dprintf(CRITICAL, "%s: No MTK WDT Common Driver API\n", __func__);
+}
+
+void mrdump_key_fdt_init(void *fdt)
+{
+	dprintf(CRITICAL, "%s: No MTK WDT Common Driver API\n", __func__);
+}
+
+#else
+
+#include <platform/mt_gpio.h>
+#include <platform/mt_typedefs.h>
+#include <mtk_wdt.h>
+#include <pmic_common.h>
+#include <printf.h>
+
+static void mrdump_key_select_eint(int mrdump_key_pin)
+{
+	mt_set_gpio_pull_enable(mrdump_key_pin, GPIO_PULL_UP);
+	mt_set_gpio_dir(mrdump_key_pin, GPIO_DIR_IN);
+	mt_set_gpio_mode(mrdump_key_pin, GPIO_MODE_00);
+
+	mtk_wdt_select_eint((unsigned int)mrdump_key_pin);
+}
+
+static void mrdump_key_apply(char *force_trigger,  char *rst_mode,
+		int mrdump_key_pin)
+{
+	if (!rst_mode || !force_trigger) {
+		dprintf(CRITICAL, "%s: no rst_mode or force_trigger\n",
+			__func__);
+		return;
+	}
+
+	if (!strncmp("SYSRST", force_trigger, strlen("SYSRST"))) {
+		if (!strncmp(rst_mode, "IRQ", strlen("IRQ"))) {
+			mtk_wdt_request_mode_set(MTK_WDT_STATUS_SYSRST_RST,
+						 WD_REQ_IRQ_MODE);
+			mtk_wdt_request_en_set(MTK_WDT_STATUS_SYSRST_RST,
+					       WD_REQ_EN);
+			enable_pmic_smart_reset(1);          /* 1st timeout */
+			enable_pmic_smart_reset_shutdown(1); /* 2nd timeout */
+		} else if (!strncmp(rst_mode, "RST", strlen("RST"))) {
+			mtk_wdt_request_mode_set(MTK_WDT_STATUS_SYSRST_RST,
+						 WD_REQ_RST_MODE);
+			mtk_wdt_request_en_set(MTK_WDT_STATUS_SYSRST_RST,
+					       WD_REQ_EN);
+			enable_pmic_smart_reset(1);
+			enable_pmic_smart_reset_shutdown(1);
+		} else {
+			dprintf(CRITICAL, "%s: bad rst_mode=%s in SYSRST\n",
+					   __func__, rst_mode);
+		}
+	} else if (!strncmp("EINT", force_trigger, strlen("EINT"))) {
+		if ((mrdump_key_pin < 0) || (mrdump_key_pin >12)) {
+			dprintf(CRITICAL, "%s: incorrect mrdump_key_pin(%d)\n",
+				__func__, mrdump_key_pin);
+			return;
+		}
+
+		mrdump_key_select_eint(mrdump_key_pin);
+
+		if (rst_mode && !strncmp(rst_mode, "IRQ", strlen("IRQ"))) {
+			mtk_wdt_request_mode_set(MTK_WDT_STATUS_EINT_RST,
+						 WD_REQ_IRQ_MODE);
+			mtk_wdt_request_en_set(MTK_WDT_STATUS_EINT_RST,
+					       WD_REQ_EN);
+		} else if (rst_mode && !strncmp(rst_mode, "RST", strlen("RST"))) {
+			mtk_wdt_request_mode_set(MTK_WDT_STATUS_EINT_RST,
+						 WD_REQ_RST_MODE);
+			mtk_wdt_request_en_set(MTK_WDT_STATUS_EINT_RST,
+					       WD_REQ_EN);
+		} else {
+			dprintf(CRITICAL, "%s: bad rst_mode=%s in EINT\n",
+					   __func__, rst_mode);
+		}
+	} else {
+		dprintf(CRITICAL, "%s: no valid force_trigger info (%s)\n",
+				   __func__, force_trigger);
+	}
+}
+
+static char *force_mode;
+
+void mrdump_key_secure_enable(void)
+{
+	force_mode = "SYSRST";
+}
+
+void mrdump_key_fdt_init(void *fdt)
+{
+	const char mrdump_key_compatible[] = "mediatek, mrdump_ext_rst-eint";
+	int offset, len;
+	const void *data;
+
+	int mrdump_key_pin, *interrupts;
+	char *rst_mode = "IRQ";
+
+	if (!force_mode) {
+#if defined(USER_BUILD)
+		force_mode = "EINT";
+#else
+		force_mode = "SYSRST";
+#endif
+		dprintf(CRITICAL, "%s: force trigger default to %s\n", __func__, force_mode);
+	} else {
+		dprintf(CRITICAL, "%s: force trigger set to %s\n", __func__, force_mode);
+	}
+
+	offset = fdt_node_offset_by_compatible(fdt, -1, mrdump_key_compatible);
+	if (offset < 0) {
+		dprintf(CRITICAL, "%s not found\n", mrdump_key_compatible);
+		return;
+	}
+
+	data = fdt_getprop(fdt, offset, "force_mode", &len);
+	if (data) {
+		dprintf(CRITICAL, "%s: force_mode = %s\n", __func__, (char *)data);
+		force_mode = (char *)data;
+	} else {
+		dprintf(CRITICAL, "%s: no force_mode attribute default=%s\n",
+			__func__, force_mode);
+	}
+
+	data = fdt_getprop(fdt, offset, "mode", &len);
+	if (data) {
+		dprintf(CRITICAL, "%s: rst_mode = %s\n", __func__, (char *)data);
+		rst_mode = (char *)data;
+	} else
+		dprintf(CRITICAL, "%s: no mode attribute default=%s\n",
+			__func__, rst_mode);
+
+	data = fdt_getprop(fdt, offset, "interrupts", &len);
+	if (data) {
+		dprintf(CRITICAL, "%s: interrupts = 0x%x\n", __func__, *((int *)data));
+		interrupts = (int *)data;
+		mrdump_key_pin = (*interrupts/0x1000000);
+		dprintf(CRITICAL, "%s: mrdump_key_pin = EINT%d\n", __func__, mrdump_key_pin);
+	} else {
+		dprintf(CRITICAL, "%s: no interrupts attribute\n", __func__);
+		mrdump_key_pin = -1;
+	}
+
+	mrdump_key_apply(force_mode, rst_mode, mrdump_key_pin);
+}
+#endif

+ 441 - 0
app/mt_boot/aee/mrdump_mpart.c

@@ -0,0 +1,441 @@
+/* Copyright Statement:
+*
+* This software/firmware and related documentation ("MediaTek Software") are
+* protected under relevant copyright laws. The information contained herein
+* is confidential and proprietary to MediaTek Inc. and/or its licensors.
+* Without the prior written permission of MediaTek inc. and/or its licensors,
+* any reproduction, modification, use or disclosure of MediaTek Software,
+* and information contained herein, in whole or in part, shall be strictly prohibited.
+*/
+/* MediaTek Inc. (C) 2018. All rights reserved.
+*
+* BY OPENING THIS FILE, RECEIVER HEREBY UNEQUIVOCALLY ACKNOWLEDGES AND AGREES
+* THAT THE SOFTWARE/FIRMWARE AND ITS DOCUMENTATIONS ("MEDIATEK SOFTWARE")
+* RECEIVED FROM MEDIATEK AND/OR ITS REPRESENTATIVES ARE PROVIDED TO RECEIVER ON
+* AN "AS-IS" BASIS ONLY. MEDIATEK EXPRESSLY DISCLAIMS ANY AND ALL WARRANTIES,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED WARRANTIES OF
+* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE OR NONINFRINGEMENT.
+* NEITHER DOES MEDIATEK PROVIDE ANY WARRANTY WHATSOEVER WITH RESPECT TO THE
+* SOFTWARE OF ANY THIRD PARTY WHICH MAY BE USED BY, INCORPORATED IN, OR
+* SUPPLIED WITH THE MEDIATEK SOFTWARE, AND RECEIVER AGREES TO LOOK ONLY TO SUCH
+* THIRD PARTY FOR ANY WARRANTY CLAIM RELATING THERETO. RECEIVER EXPRESSLY ACKNOWLEDGES
+* THAT IT IS RECEIVER'S SOLE RESPONSIBILITY TO OBTAIN FROM ANY THIRD PARTY ALL PROPER LICENSES
+* CONTAINED IN MEDIATEK SOFTWARE. MEDIATEK SHALL ALSO NOT BE RESPONSIBLE FOR ANY MEDIATEK
+* SOFTWARE RELEASES MADE TO RECEIVER'S SPECIFICATION OR TO CONFORM TO A PARTICULAR
+* STANDARD OR OPEN FORUM. RECEIVER'S SOLE AND EXCLUSIVE REMEDY AND MEDIATEK'S ENTIRE AND
+* CUMULATIVE LIABILITY WITH RESPECT TO THE MEDIATEK SOFTWARE RELEASED HEREUNDER WILL BE,
+* AT MEDIATEK'S OPTION, TO REVISE OR REPLACE THE MEDIATEK SOFTWARE AT ISSUE,
+* OR REFUND ANY SOFTWARE LICENSE FEES OR SERVICE CHARGE PAID BY RECEIVER TO
+* MEDIATEK FOR SUCH MEDIATEK SOFTWARE AT ISSUE.
+*/
+
+#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 <platform/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) {
+		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 = total_dump_size / dev->blkdev->blksz;
+	u64 data_total_sect, mrdump_total_sect;
+	u64 sz;
+	u8 *data;
+
+	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__);
+}

+ 67 - 0
app/mt_boot/aee/mrdump_null.c

@@ -0,0 +1,67 @@
+/* Copyright Statement:
+*
+* This software/firmware and related documentation ("MediaTek Software") are
+* protected under relevant copyright laws. The information contained herein
+* is confidential and proprietary to MediaTek Inc. and/or its licensors.
+* Without the prior written permission of MediaTek inc. and/or its licensors,
+* any reproduction, modification, use or disclosure of MediaTek Software,
+* and information contained herein, in whole or in part, shall be strictly prohibited.
+*/
+/* MediaTek Inc. (C) 2016. All rights reserved.
+*
+* BY OPENING THIS FILE, RECEIVER HEREBY UNEQUIVOCALLY ACKNOWLEDGES AND AGREES
+* THAT THE SOFTWARE/FIRMWARE AND ITS DOCUMENTATIONS ("MEDIATEK SOFTWARE")
+* RECEIVED FROM MEDIATEK AND/OR ITS REPRESENTATIVES ARE PROVIDED TO RECEIVER ON
+* AN "AS-IS" BASIS ONLY. MEDIATEK EXPRESSLY DISCLAIMS ANY AND ALL WARRANTIES,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED WARRANTIES OF
+* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE OR NONINFRINGEMENT.
+* NEITHER DOES MEDIATEK PROVIDE ANY WARRANTY WHATSOEVER WITH RESPECT TO THE
+* SOFTWARE OF ANY THIRD PARTY WHICH MAY BE USED BY, INCORPORATED IN, OR
+* SUPPLIED WITH THE MEDIATEK SOFTWARE, AND RECEIVER AGREES TO LOOK ONLY TO SUCH
+* THIRD PARTY FOR ANY WARRANTY CLAIM RELATING THERETO. RECEIVER EXPRESSLY ACKNOWLEDGES
+* THAT IT IS RECEIVER'S SOLE RESPONSIBILITY TO OBTAIN FROM ANY THIRD PARTY ALL PROPER LICENSES
+* CONTAINED IN MEDIATEK SOFTWARE. MEDIATEK SHALL ALSO NOT BE RESPONSIBLE FOR ANY MEDIATEK
+* SOFTWARE RELEASES MADE TO RECEIVER'S SPECIFICATION OR TO CONFORM TO A PARTICULAR
+* STANDARD OR OPEN FORUM. RECEIVER'S SOLE AND EXCLUSIVE REMEDY AND MEDIATEK'S ENTIRE AND
+* CUMULATIVE LIABILITY WITH RESPECT TO THE MEDIATEK SOFTWARE RELEASED HEREUNDER WILL BE,
+* AT MEDIATEK'S OPTION, TO REVISE OR REPLACE THE MEDIATEK SOFTWARE AT ISSUE,
+* OR REFUND ANY SOFTWARE LICENSE FEES OR SERVICE CHARGE PAID BY RECEIVER TO
+* MEDIATEK FOR SUCH MEDIATEK SOFTWARE AT ISSUE.
+*/
+
+#include <stdint.h>
+#include <platform/mt_typedefs.h>
+#include <platform/mtk_wdt.h>
+
+#include "aee.h"
+#include "mrdump_private.h"
+
+static int null_write_cb(void *handle, void *buf, int size)
+{
+	return size;
+}
+
+int mrdump_null_output(const struct mrdump_control_block *mrdump_cb, const struct kzip_addlist *memlist, const struct kzip_addlist *memlist_cmm)
+{
+	voprintf_info("Output to null\n");
+	mtk_wdt_restart();
+
+	bool ok = true;
+	mtk_wdt_restart();
+	struct kzip_file *zf = kzip_open(NULL, null_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;
+		kzip_close(zf);
+		zf = NULL;
+	} else {
+		ok = false;
+	}
+	mtk_wdt_restart();
+	if (ok) {
+		mrdump_status_ok("NULL-OUTPUT\n");
+	}
+	return ok ? 0 : -1;
+}

+ 262 - 0
app/mt_boot/aee/mrdump_private.h

@@ -0,0 +1,262 @@
+/* Copyright Statement:
+*
+* This software/firmware and related documentation ("MediaTek Software") are
+* protected under relevant copyright laws. The information contained herein
+* is confidential and proprietary to MediaTek Inc. and/or its licensors.
+* Without the prior written permission of MediaTek inc. and/or its licensors,
+* any reproduction, modification, use or disclosure of MediaTek Software,
+* and information contained herein, in whole or in part, shall be strictly prohibited.
+*/
+/* MediaTek Inc. (C) 2016. All rights reserved.
+*
+* BY OPENING THIS FILE, RECEIVER HEREBY UNEQUIVOCALLY ACKNOWLEDGES AND AGREES
+* THAT THE SOFTWARE/FIRMWARE AND ITS DOCUMENTATIONS ("MEDIATEK SOFTWARE")
+* RECEIVED FROM MEDIATEK AND/OR ITS REPRESENTATIVES ARE PROVIDED TO RECEIVER ON
+* AN "AS-IS" BASIS ONLY. MEDIATEK EXPRESSLY DISCLAIMS ANY AND ALL WARRANTIES,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED WARRANTIES OF
+* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE OR NONINFRINGEMENT.
+* NEITHER DOES MEDIATEK PROVIDE ANY WARRANTY WHATSOEVER WITH RESPECT TO THE
+* SOFTWARE OF ANY THIRD PARTY WHICH MAY BE USED BY, INCORPORATED IN, OR
+* SUPPLIED WITH THE MEDIATEK SOFTWARE, AND RECEIVER AGREES TO LOOK ONLY TO SUCH
+* THIRD PARTY FOR ANY WARRANTY CLAIM RELATING THERETO. RECEIVER EXPRESSLY ACKNOWLEDGES
+* THAT IT IS RECEIVER'S SOLE RESPONSIBILITY TO OBTAIN FROM ANY THIRD PARTY ALL PROPER LICENSES
+* CONTAINED IN MEDIATEK SOFTWARE. MEDIATEK SHALL ALSO NOT BE RESPONSIBLE FOR ANY MEDIATEK
+* SOFTWARE RELEASES MADE TO RECEIVER'S SPECIFICATION OR TO CONFORM TO A PARTICULAR
+* STANDARD OR OPEN FORUM. RECEIVER'S SOLE AND EXCLUSIVE REMEDY AND MEDIATEK'S ENTIRE AND
+* CUMULATIVE LIABILITY WITH RESPECT TO THE MEDIATEK SOFTWARE RELEASED HEREUNDER WILL BE,
+* AT MEDIATEK'S OPTION, TO REVISE OR REPLACE THE MEDIATEK SOFTWARE AT ISSUE,
+* OR REFUND ANY SOFTWARE LICENSE FEES OR SERVICE CHARGE PAID BY RECEIVER TO
+* MEDIATEK FOR SUCH MEDIATEK SOFTWARE AT ISSUE.
+*/
+
+#if !defined(__MRDUMP_PRIVATE_H__)
+#define __MRDUMP_PRIVATE_H__
+
+#include <stdint.h>
+#include <platform/mt_typedefs.h>
+#include <platform/mt_reg_base.h>
+#include <dev/mrdump.h>
+
+#include <platform/mtk_mrdump.h>
+
+/* for LPAE (MTK_3LEVEL_PAGETABLE) */
+#include <compiler.h>
+#include <arch/arm/mmu.h>
+
+#define MRDUMP_GO_DUMP "MRDUMP09"
+
+#define MRDUMP_LINUX_KERNEL_MEMORY "linux-kernel-memory"
+
+/*
+ * for ext4 and f2fs, InfoLBA (header), version 2
+ * v1: support allocate size > 4G
+ * v2: support timestamp
+ */
+#define MRDUMP_PAF_VERSION 0x0002
+
+#define MRDUMP_PAF_INFO_LBA      4
+#define MRDUMP_PAF_ADDR_LBA      8
+#define MRDUMP_PAF_ALLOCSIZE    12
+#define MRDUMP_PAF_COREDUMPSIZE 20
+#define MRDUMP_PAF_TIMESTAMP    28
+#define MRDUMP_PAF_CRC32        36
+#define MRDUMP_LBA_DATAONLY     MRDUMP_PAF_CRC32
+#define MRDUMP_PAF_TOTAL_SIZE   40
+
+#define KZIP_ENTRY_MAX 64
+#define LOCALHEADERMAGIC 0x04034b50UL
+#define CENTRALHEADERMAGIC 0x02014b50UL
+#define ZIP64ENDOFCENTRALDIRMAGIC 0x06064b50UL
+#define ZIP64ENDOFCENTRALDIRLOCATORMAGIC 0x07064b50UL
+#define ENDOFCENTRALDIRMAGIC 0x06054b50UL
+
+#define MRDUMP_CORE_HEADER_SIZE 2 * 4096
+
+struct kzip_entry {
+	char *filename;
+	int level;
+	uint64_t localheader_offset;
+	uint64_t comp_size;
+	uint64_t uncomp_size;
+	uint32_t crc32;
+};
+
+struct kzip_file {
+	uint64_t reported_size;
+	uint64_t wdk_kick_size;
+	uint64_t current_size;
+
+	uint32_t entries_num;
+	struct kzip_entry zentries[KZIP_ENTRY_MAX];
+	void *handle;
+
+	int (*write_cb)(void *handle, void *buf, int size);
+};
+
+#define MEM_NO_MAP 0
+#define MEM_DO_MAP 1
+#define EXPDB_FILE 2
+struct kzip_addlist {
+	uint64_t address;
+	uint64_t size;
+	uint32_t type;
+	uint64_t memmap;
+	uint64_t pageflags;
+	uint32_t struct_page_size;
+};
+
+#define MRDUMP_CPU_MAX 12
+
+#define MRDUMP_ENABLE_COOKIE 0x590d2ba3
+
+typedef uint32_t arm32_gregset_t[18];
+typedef uint64_t arm64_gregset_t[34];
+
+struct arm32_ctrl_regs {
+	uint32_t sctlr;
+	uint64_t ttbcr;
+	uint64_t ttbr0;
+	uint64_t ttbr1;
+};
+
+struct arm64_ctrl_regs {
+	uint32_t sctlr_el1;
+	uint32_t sctlr_el2;
+	uint32_t sctlr_el3;
+
+	uint64_t tcr_el1;
+	uint64_t tcr_el2;
+	uint64_t tcr_el3;
+
+	uint64_t ttbr0_el1;
+	uint64_t ttbr0_el2;
+	uint64_t ttbr0_el3;
+
+	uint64_t ttbr1_el1;
+
+	uint64_t sp_el[4];
+};
+
+struct mrdump_crash_record {
+	int reboot_mode;
+
+	char msg[128];
+
+	uint32_t fault_cpu;
+
+	union {
+		arm32_gregset_t arm32_regs;
+		arm64_gregset_t arm64_regs;
+	} cpu_regs[MRDUMP_CPU_MAX];
+
+	union {
+		struct arm32_ctrl_regs arm32_creg;
+		struct arm64_ctrl_regs arm64_creg;
+	} cpu_creg[MRDUMP_CPU_MAX];
+};
+
+struct mrdump_ksyms_param {
+	char     tag[4];
+	uint32_t flag;
+	uint32_t crc;
+	uint64_t start_addr;
+	uint32_t size;
+	uint32_t addresses_off;
+	uint32_t num_syms_off;
+	uint32_t names_off;
+	uint32_t markers_off;
+	uint32_t token_table_off;
+	uint32_t token_index_off;
+} __attribute__((packed));
+
+struct mrdump_machdesc {
+	uint32_t nr_cpus;
+
+	uint64_t page_offset;
+	uint64_t high_memory;
+
+	uint64_t kimage_vaddr;
+	uint64_t dram_start;
+	uint64_t dram_end;
+	uint64_t kimage_stext;
+	uint64_t kimage_etext;
+	uint64_t kimage_stext_real;
+	uint64_t kimage_voffset;
+	uint64_t kimage_sdata;
+	uint64_t kimage_edata;
+
+	uint64_t vmalloc_start;
+	uint64_t vmalloc_end;
+
+	uint64_t modules_start;
+	uint64_t modules_end;
+
+	uint64_t phys_offset;
+	uint64_t master_page_table;
+
+	uint64_t memmap;
+	uint64_t pageflags;
+	uint32_t struct_page_size;
+
+	uint64_t dfdmem_pa;  // Reserved for DFD 3.0+
+
+	struct mrdump_ksyms_param kallsyms;
+};
+
+struct __attribute__((__packed__)) mrdump_cblock_result {
+	char sig[9];
+	char status[128];
+	char log_buf[2048];
+};
+
+struct mrdump_control_block {
+	char sig[8];
+
+	struct mrdump_machdesc machdesc;
+	uint32_t machdesc_crc;
+
+	uint32_t enabled;
+	uint32_t output_fs_lbaooo;
+
+	struct mrdump_crash_record crash_record;
+};
+
+struct kzip_file *kzip_open(void *handle, int (*write_cb)(void *handle, void *p, int size));
+bool kzip_add_file(struct kzip_file *zf, const struct kzip_addlist *addlist, const char *zfilename);
+bool kzip_close(struct kzip_file *zf);
+
+struct mrdump_dev {
+	const char *name;
+	void *handle;
+
+	bool (*read)(struct mrdump_dev *dev, uint64_t sector_addr, uint8_t *pdBuf, int32_t blockLen);
+	bool (*write)(struct mrdump_dev *dev, uint64_t sector_addr, uint8_t *pdBuf, int32_t blockLen);
+	uint64_t (*get_size)(struct mrdump_dev *dev);
+};
+
+int mrdump_null_output(const struct mrdump_control_block *kparams, const struct kzip_addlist *memlist, const struct kzip_addlist *memlist_cmm);
+int mrdump_ext4_output(const struct mrdump_control_block *mrdump_cb, const struct kzip_addlist *memlist, const struct kzip_addlist *memlist_cmm, struct mrdump_dev *mrdump_dev);
+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);
+int mrdump_usb_output(const struct mrdump_control_block *mrdump_cb, const struct kzip_addlist *memlist, const struct kzip_addlist *memlist_cmm);
+
+void mrdump_core_header_init(const struct mrdump_control_block *kparams, const struct kzip_addlist *memlist);
+
+struct kzip_addlist *mrdump_memlist_fill_cmm(struct mrdump_control_block *mrdump_cblock);
+void mrdump_memlist_free_cmm(struct kzip_addlist *memlist);
+
+struct mrdump_dev *mrdump_dev_blkpart(const char *partname);
+void mrdump_partition_resize(void);
+void mrdump_read_expdb(void *data, int len, u64 offset_src);
+
+extern u64 physical_memory_size(void);
+extern void mtk_wdt_disable(void);
+extern void mtk_wdt_init(void);
+
+int aee_mrdump_get_info(struct mrdump_control_block *mcb);
+int mrdump_get_default_output_device(void);
+
+#ifdef MTK_3LEVEL_PAGETABLE
+vaddr_t scratch_addr(void);
+#endif
+
+#endif

+ 109 - 0
app/mt_boot/aee/mrdump_rsvmem.c

@@ -0,0 +1,109 @@
+/* Copyright Statement:
+*
+* This software/firmware and related documentation ("MediaTek Software") are
+* protected under relevant copyright laws. The information contained herein
+* is confidential and proprietary to MediaTek Inc. and/or its licensors.
+* Without the prior written permission of MediaTek inc. and/or its licensors,
+* any reproduction, modification, use or disclosure of MediaTek Software,
+* and information contained herein, in whole or in part, shall be strictly prohibited.
+*/
+/* MediaTek Inc. (C) 2016. All rights reserved.
+*
+* BY OPENING THIS FILE, RECEIVER HEREBY UNEQUIVOCALLY ACKNOWLEDGES AND AGREES
+* THAT THE SOFTWARE/FIRMWARE AND ITS DOCUMENTATIONS ("MEDIATEK SOFTWARE")
+* RECEIVED FROM MEDIATEK AND/OR ITS REPRESENTATIVES ARE PROVIDED TO RECEIVER ON
+* AN "AS-IS" BASIS ONLY. MEDIATEK EXPRESSLY DISCLAIMS ANY AND ALL WARRANTIES,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED WARRANTIES OF
+* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE OR NONINFRINGEMENT.
+* NEITHER DOES MEDIATEK PROVIDE ANY WARRANTY WHATSOEVER WITH RESPECT TO THE
+* SOFTWARE OF ANY THIRD PARTY WHICH MAY BE USED BY, INCORPORATED IN, OR
+* SUPPLIED WITH THE MEDIATEK SOFTWARE, AND RECEIVER AGREES TO LOOK ONLY TO SUCH
+* THIRD PARTY FOR ANY WARRANTY CLAIM RELATING THERETO. RECEIVER EXPRESSLY ACKNOWLEDGES
+* THAT IT IS RECEIVER'S SOLE RESPONSIBILITY TO OBTAIN FROM ANY THIRD PARTY ALL PROPER LICENSES
+* CONTAINED IN MEDIATEK SOFTWARE. MEDIATEK SHALL ALSO NOT BE RESPONSIBLE FOR ANY MEDIATEK
+* SOFTWARE RELEASES MADE TO RECEIVER'S SPECIFICATION OR TO CONFORM TO A PARTICULAR
+* STANDARD OR OPEN FORUM. RECEIVER'S SOLE AND EXCLUSIVE REMEDY AND MEDIATEK'S ENTIRE AND
+* CUMULATIVE LIABILITY WITH RESPECT TO THE MEDIATEK SOFTWARE RELEASED HEREUNDER WILL BE,
+* AT MEDIATEK'S OPTION, TO REVISE OR REPLACE THE MEDIATEK SOFTWARE AT ISSUE,
+* OR REFUND ANY SOFTWARE LICENSE FEES OR SERVICE CHARGE PAID BY RECEIVER TO
+* MEDIATEK FOR SUCH MEDIATEK SOFTWARE AT ISSUE.
+*/
+
+#include <memory_layout.h>
+#include <malloc.h>
+#include <printf.h>
+#include <stdarg.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <string.h>
+#include <libfdt.h>
+
+#include <platform/mt_typedefs.h>
+#include <platform/boot_mode.h>
+#include <mt_boot.h>
+#include <mblock.h>
+#include <platform.h>
+
+#include <dev/mrdump.h>
+#include "aee.h"
+#include "mrdump_private.h"
+
+void mrdump_reserve_memory(void)
+{
+#if defined(MBLOCK_LIB_SUPPORT)
+#if	defined(MBLOCK_LIB_SUPPORT) \
+	&& (MBLOCK_EXPAND(MBLOCK_LIB_SUPPORT)\
+	== MBLOCK_EXPAND(2))
+
+	if (mrdump_check_enable() <= MRDUMP_ALWAYS_ENABLE) {
+#if defined (MEMSIZE) && defined(SECTION_SIZE)
+		(void)mblock_reserve_ext(&g_boot_arg->mblock_info,
+					 MEMSIZE, SECTION_SIZE, (MEMBASE + MEMSIZE),
+					 0, "lk_addr_mrdump");
+#endif
+#if defined(LK_DT_BASE)
+		(void)mblock_reserve_ext(&g_boot_arg->mblock_info,
+					 DTB_MAX_SIZE, DTB_MAX_SIZE,
+					 (LK_DT_BASE + DTB_MAX_SIZE),
+					 1, "dtb_addr_mrdump");
+#endif
+	}
+	else {
+#ifdef PL_DRAMBUF_BASE
+		if (mblock_query_reserved(&g_boot_arg->mblock_info,
+					  "pl-drambuf", 0)) {
+			if (mblock_create(&g_boot_arg->mblock_info,
+					  &g_boot_arg->orig_dram_info,
+					  PL_DRAMBUF_BASE, PL_DRAMBUF_MAX_SIZE)) {
+				dprintf(CRITICAL, "%s: free PL_DRAMBUF_ARG failed\n", __func__);
+				assert(0);
+			}
+		}
+#endif /* end of PL_DRAMBUF_BASE */
+#ifdef PL_BOOTTAGS_BASE
+		if (mblock_query_reserved(&g_boot_arg->mblock_info,
+					  "pl-boottag", 0)) {
+			if (mblock_create(&g_boot_arg->mblock_info,
+					  &g_boot_arg->orig_dram_info,
+					  PL_BOOTTAGS_BASE, PL_BOOTTAGS_MAX_SIZE)) {
+				dprintf(CRITICAL, "%s: free PL_BOOT_ARG failed\n", __func__);
+				assert(0);
+			}
+		}
+#endif /* end of PL_BOOTTAGS_BASE */
+#ifdef PL_BOOTARG_BASE
+		if (mblock_query_reserved(&g_boot_arg->mblock_info,
+					  "pl-bootarg", 0)) {
+			if (mblock_create(&g_boot_arg->mblock_info,
+					  &g_boot_arg->orig_dram_info,
+					  PL_BOOTARG_BASE, PL_BOOTARG_MAX_SIZE)) {
+				dprintf(CRITICAL, "%s: free PL_BOOT_ARG failed\n", __func__);
+				assert(0);
+			}
+		}
+#endif /* end of PL_BOOTARG_BASE */
+	}
+#endif
+#endif
+}
+

+ 91 - 0
app/mt_boot/aee/mrdump_sddev.c

@@ -0,0 +1,91 @@
+/* Copyright Statement:
+*
+* This software/firmware and related documentation ("MediaTek Software") are
+* protected under relevant copyright laws. The information contained herein
+* is confidential and proprietary to MediaTek Inc. and/or its licensors.
+* Without the prior written permission of MediaTek inc. and/or its licensors,
+* any reproduction, modification, use or disclosure of MediaTek Software,
+* and information contained herein, in whole or in part, shall be strictly prohibited.
+*/
+/* MediaTek Inc. (C) 2016. All rights reserved.
+*
+* BY OPENING THIS FILE, RECEIVER HEREBY UNEQUIVOCALLY ACKNOWLEDGES AND AGREES
+* THAT THE SOFTWARE/FIRMWARE AND ITS DOCUMENTATIONS ("MEDIATEK SOFTWARE")
+* RECEIVED FROM MEDIATEK AND/OR ITS REPRESENTATIVES ARE PROVIDED TO RECEIVER ON
+* AN "AS-IS" BASIS ONLY. MEDIATEK EXPRESSLY DISCLAIMS ANY AND ALL WARRANTIES,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED WARRANTIES OF
+* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE OR NONINFRINGEMENT.
+* NEITHER DOES MEDIATEK PROVIDE ANY WARRANTY WHATSOEVER WITH RESPECT TO THE
+* SOFTWARE OF ANY THIRD PARTY WHICH MAY BE USED BY, INCORPORATED IN, OR
+* SUPPLIED WITH THE MEDIATEK SOFTWARE, AND RECEIVER AGREES TO LOOK ONLY TO SUCH
+* THIRD PARTY FOR ANY WARRANTY CLAIM RELATING THERETO. RECEIVER EXPRESSLY ACKNOWLEDGES
+* THAT IT IS RECEIVER'S SOLE RESPONSIBILITY TO OBTAIN FROM ANY THIRD PARTY ALL PROPER LICENSES
+* CONTAINED IN MEDIATEK SOFTWARE. MEDIATEK SHALL ALSO NOT BE RESPONSIBLE FOR ANY MEDIATEK
+* SOFTWARE RELEASES MADE TO RECEIVER'S SPECIFICATION OR TO CONFORM TO A PARTICULAR
+* STANDARD OR OPEN FORUM. RECEIVER'S SOLE AND EXCLUSIVE REMEDY AND MEDIATEK'S ENTIRE AND
+* CUMULATIVE LIABILITY WITH RESPECT TO THE MEDIATEK SOFTWARE RELEASED HEREUNDER WILL BE,
+* AT MEDIATEK'S OPTION, TO REVISE OR REPLACE THE MEDIATEK SOFTWARE AT ISSUE,
+* OR REFUND ANY SOFTWARE LICENSE FEES OR SERVICE CHARGE PAID BY RECEIVER TO
+* MEDIATEK FOR SUCH MEDIATEK SOFTWARE AT ISSUE.
+*/
+
+#include <malloc.h>
+#include <stddef.h>
+#include <stdint.h>
+#include <string.h>
+#include <block_generic_interface.h>
+#include <part_interface.h>
+#include <part_status.h>
+
+#include "aee.h"
+#include "mrdump_private.h"
+
+static uint64_t part_device_get_size(struct mrdump_dev *dev)
+{
+	if (dev == NULL) {
+		voprintf_error("%s dev is NULL!\n", __func__);
+		return 0;
+	} else {
+		return partition_get_size_by_name(dev->handle);
+	}
+}
+
+static bool part_device_read(struct mrdump_dev *dev, uint64_t offset, uint8_t *buf, int32_t len)
+{
+	if (dev == NULL) {
+		voprintf_error("%s dev is NULL!\n", __func__);
+		return false;
+	} else {
+		return partition_read(dev->handle, offset, buf, len) == len;
+	}
+}
+
+static bool part_device_write(struct mrdump_dev *dev, uint64_t offset, uint8_t *buf, int32_t len)
+{
+	if (dev == NULL) {
+		voprintf_error("%s dev is NULL!\n", __func__);
+		return false;
+	} else {
+		return partition_write(dev->handle, offset, buf, len) == len;
+	}
+}
+
+struct mrdump_dev *mrdump_dev_blkpart(const char *partname)
+{
+	if (partition_exists(partname) != PART_OK) {
+		voprintf_error("Can't find partition %s\n", partname);
+		return NULL;
+	}
+        struct mrdump_dev *dev = malloc(sizeof(struct mrdump_dev));
+        if (!dev) {
+                voprintf_error("%s: malloc() failed!\n", __func__);
+                return NULL;
+        }
+
+        dev->name = "blkpart";
+        dev->handle = (void *)strdup(partname);
+        dev->read = part_device_read;
+        dev->write = part_device_write;
+	dev->get_size = part_device_get_size;
+        return dev;
+}

+ 141 - 0
app/mt_boot/aee/mrdump_setup.c

@@ -0,0 +1,141 @@
+/* Copyright Statement:
+*
+* This software/firmware and related documentation ("MediaTek Software") are
+* protected under relevant copyright laws. The information contained herein
+* is confidential and proprietary to MediaTek Inc. and/or its licensors.
+* Without the prior written permission of MediaTek inc. and/or its licensors,
+* any reproduction, modification, use or disclosure of MediaTek Software,
+* and information contained herein, in whole or in part, shall be strictly prohibited.
+*/
+/* MediaTek Inc. (C) 2016. All rights reserved.
+*
+* BY OPENING THIS FILE, RECEIVER HEREBY UNEQUIVOCALLY ACKNOWLEDGES AND AGREES
+* THAT THE SOFTWARE/FIRMWARE AND ITS DOCUMENTATIONS ("MEDIATEK SOFTWARE")
+* RECEIVED FROM MEDIATEK AND/OR ITS REPRESENTATIVES ARE PROVIDED TO RECEIVER ON
+* AN "AS-IS" BASIS ONLY. MEDIATEK EXPRESSLY DISCLAIMS ANY AND ALL WARRANTIES,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED WARRANTIES OF
+* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE OR NONINFRINGEMENT.
+* NEITHER DOES MEDIATEK PROVIDE ANY WARRANTY WHATSOEVER WITH RESPECT TO THE
+* SOFTWARE OF ANY THIRD PARTY WHICH MAY BE USED BY, INCORPORATED IN, OR
+* SUPPLIED WITH THE MEDIATEK SOFTWARE, AND RECEIVER AGREES TO LOOK ONLY TO SUCH
+* THIRD PARTY FOR ANY WARRANTY CLAIM RELATING THERETO. RECEIVER EXPRESSLY ACKNOWLEDGES
+* THAT IT IS RECEIVER'S SOLE RESPONSIBILITY TO OBTAIN FROM ANY THIRD PARTY ALL PROPER LICENSES
+* CONTAINED IN MEDIATEK SOFTWARE. MEDIATEK SHALL ALSO NOT BE RESPONSIBLE FOR ANY MEDIATEK
+* SOFTWARE RELEASES MADE TO RECEIVER'S SPECIFICATION OR TO CONFORM TO A PARTICULAR
+* STANDARD OR OPEN FORUM. RECEIVER'S SOLE AND EXCLUSIVE REMEDY AND MEDIATEK'S ENTIRE AND
+* CUMULATIVE LIABILITY WITH RESPECT TO THE MEDIATEK SOFTWARE RELEASED HEREUNDER WILL BE,
+* AT MEDIATEK'S OPTION, TO REVISE OR REPLACE THE MEDIATEK SOFTWARE AT ISSUE,
+* OR REFUND ANY SOFTWARE LICENSE FEES OR SERVICE CHARGE PAID BY RECEIVER TO
+* MEDIATEK FOR SUCH MEDIATEK SOFTWARE AT ISSUE.
+*/
+
+#include <block_generic_interface.h>
+#include <malloc.h>
+#include <printf.h>
+#include <stdarg.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <string.h>
+#include <video.h>
+#include <dev/mrdump.h>
+#include <platform/mtk_key.h>
+#include <platform/mtk_wdt.h>
+#include <platform/mt_gpt.h>
+#include <target/cust_key.h>
+#include <platform/boot_mode.h>
+#include <platform/ram_console.h>
+#include <arch/ops.h>
+#include <libfdt.h>
+#include <platform.h>
+#include "aee.h"
+#include "mrdump_private.h"
+
+/* +++ ddr reserve mode +++ */
+extern BOOT_ARGUMENT *g_boot_arg;
+
+static void mrdump_ddr_rsv_fdt(void *fdt, int offset, const void *enable)
+{
+	if (0 == fdt_setprop_string(fdt, offset, "mrdump,ddr_rsv", enable)) {
+		dprintf(CRITICAL, "%s: set ddr_rsv = %s\n",
+			__func__, (char*)enable);
+	} else {
+		dprintf(CRITICAL, "%s: failed to set ddr_rsv %s\n",
+			__func__, (char*)enable);
+	}
+}
+
+/* +++ mrdump control block params +++ */
+static void mrdump_cb_fdt(void *fdt, int offset)
+{
+	int ret = fdt_setprop_u32(fdt, offset, "mrdump,cblock", MRDUMP_CB_ADDR);
+	if (ret) {
+		goto error;
+	}
+	ret = fdt_appendprop_u32(fdt, offset, "mrdump,cblock", MRDUMP_CB_SIZE);
+	if (ret) {
+		goto error;
+	}
+	return;
+error:
+	dprintf(CRITICAL, "%s: failed to set mrdump,cblock entry\n", __func__);
+}
+
+#if defined(MTK_MRDUMP_SUPPORT)
+static void mrdump_lk_version_fdt(void *fdt, int offset, const void *lk_version)
+{
+	if (0 == fdt_setprop_string(fdt, offset, "mrdump,lk", lk_version)) {
+		dprintf(CRITICAL, "%s: set lk_version = %s\n",
+			__func__, (char*)lk_version);
+	} else {
+		dprintf(CRITICAL, "%s: failed to set lk_version %s\n",
+			__func__, (char*)lk_version);
+	}
+}
+
+#endif
+
+/* +++ mrdump initialization +++ */
+void mrdump_init(void *fdt)
+{
+	int res, chosen_offset;
+
+	/* +++ mrdump_key +++ */
+	mrdump_key_fdt_init(fdt);
+
+	chosen_offset = fdt_path_offset(fdt, "/chosen");
+	if (chosen_offset < 0) {
+		dprintf(CRITICAL, "%s: /chosen not found\n", __func__);
+		return;
+	}
+
+	/* +++ ddr rsv +++ */
+	if (g_boot_arg->ddr_reserve_ready != AEE_MRDUMP_DDR_RSV_READY) {
+		mrdump_ddr_rsv_fdt(fdt, chosen_offset, "no");
+		dprintf(CRITICAL, "MT-RAMDUMP: DDR reserve mode not ready (0x%x)\n",
+			g_boot_arg->ddr_reserve_ready);
+		res = 0;
+	}
+	else {
+		mrdump_ddr_rsv_fdt(fdt, chosen_offset, "yes");
+		res = 1;
+	}
+
+	/* +++ mrdump control block params +++ */
+	mrdump_cb_fdt(fdt, chosen_offset);
+
+#if defined(MTK_MRDUMP_SUPPORT)
+	if (res && (mrdump_check_enable() <= MRDUMP_ALWAYS_ENABLE)) {
+		mrdump_lk_version_fdt(fdt, chosen_offset, MRDUMP_GO_DUMP);
+
+	}
+
+	/* default setting */
+	int output_device = mrdump_get_default_output_device();
+	if (output_device == MRDUMP_DEV_UNKNOWN)
+		dprintf(CRITICAL, "MT-RAMDUMP: unknown output device.\n");
+#endif
+
+#ifdef MRDUMP_PARTITION_ENABLE
+	mrdump_partition_resize();
+#endif
+}

+ 287 - 0
app/mt_boot/aee/mrdump_usb.c

@@ -0,0 +1,287 @@
+/* Copyright Statement:
+ *
+ * This software/firmware and related documentation ("MediaTek Software") are
+ * protected under relevant copyright laws. The information contained herein
+ * is confidential and proprietary to MediaTek Inc. and/or its licensors.
+ * Without the prior written permission of MediaTek inc. and/or its licensors,
+ * any reproduction, modification, use or disclosure of MediaTek Software,
+ * and information contained herein, in whole or in part, shall be strictly prohibited.
+ */
+/* MediaTek Inc. (C) 2017. All rights reserved.
+ *
+ * BY OPENING THIS FILE, RECEIVER HEREBY UNEQUIVOCALLY ACKNOWLEDGES AND AGREES
+ * THAT THE SOFTWARE/FIRMWARE AND ITS DOCUMENTATIONS ("MEDIATEK SOFTWARE")
+ * RECEIVED FROM MEDIATEK AND/OR ITS REPRESENTATIVES ARE PROVIDED TO RECEIVER ON
+ * AN "AS-IS" BASIS ONLY. MEDIATEK EXPRESSLY DISCLAIMS ANY AND ALL WARRANTIES,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE OR NONINFRINGEMENT.
+ * NEITHER DOES MEDIATEK PROVIDE ANY WARRANTY WHATSOEVER WITH RESPECT TO THE
+ * SOFTWARE OF ANY THIRD PARTY WHICH MAY BE USED BY, INCORPORATED IN, OR
+ * SUPPLIED WITH THE MEDIATEK SOFTWARE, AND RECEIVER AGREES TO LOOK ONLY TO SUCH
+ * THIRD PARTY FOR ANY WARRANTY CLAIM RELATING THERETO. RECEIVER EXPRESSLY ACKNOWLEDGES
+ * THAT IT IS RECEIVER\'S SOLE RESPONSIBILITY TO OBTAIN FROM ANY THIRD PARTY ALL PROPER LICENSES
+ * CONTAINED IN MEDIATEK SOFTWARE. MEDIATEK SHALL ALSO NOT BE RESPONSIBLE FOR ANY MEDIATEK
+ * SOFTWARE RELEASES MADE TO RECEIVER\'S SPECIFICATION OR TO CONFORM TO A PARTICULAR
+ * STANDARD OR OPEN FORUM. RECEIVER\'S SOLE AND EXCLUSIVE REMEDY AND MEDIATEK\'S ENTIRE AND
+ * CUMULATIVE LIABILITY WITH RESPECT TO THE MEDIATEK SOFTWARE RELEASED HEREUNDER WILL BE,
+ * AT MEDIATEK\'S OPTION, TO REVISE OR REPLACE THE MEDIATEK SOFTWARE AT ISSUE,
+ * OR REFUND ANY SOFTWARE LICENSE FEES OR SERVICE CHARGE PAID BY RECEIVER TO
+ * MEDIATEK FOR SUCH MEDIATEK SOFTWARE AT ISSUE.
+ *
+ * The following software/firmware and/or related documentation ("MediaTek Software")
+ * have been modified by MediaTek Inc. All revisions are subject to any receiver\'s
+ * applicable license agreements with MediaTek Inc.
+ */
+
+#include <dev/mrdump.h>
+#include <malloc.h>
+#include <printf.h>
+#include <platform/mt_gpt.h>
+#include <string.h>
+#include <sys/types.h>
+#include "aee.h"
+#include "mrdump_private.h"
+
+/*
+ * USB Connectivity
+ * Note: for usb transmission
+ *   QMU mode : MAX packet length: 63x1024 = 64512 byte. -> GPD_BUF_SIZE_ALIGN
+ *   ZLP issue: EXSPACE should not be multiple size of 512 byte.
+ */
+#define EXSPACE      64256
+#define MAX_RSP_SIZE 64
+#define CON_TIMEOUT  5000
+
+/* Flow control */
+#define USB_RTS      "_RTS"
+#define USB_CTS      "_CTS"
+#define USB_FIN      "_FIN"
+#define USBDONE      "DONE"
+
+/*
+ * Need to align 64 bytes to meet cache line length
+ * 1. cmd[MAX_RSP_SIZE]
+ * 2. data[EXSPACE]
+ */
+struct mrdump_usb_handle {
+	char cmd[MAX_RSP_SIZE];
+	uint8_t data[EXSPACE];
+	unsigned int zipsize;
+	int idx;
+};
+
+/* flow control of usb connection */
+static bool usb_data_transfer(struct mrdump_usb_handle *handle, int length)
+{
+	int len;
+
+	/* send RTS */
+	memset(handle->cmd, 0, MAX_RSP_SIZE);
+	len = snprintf(handle->cmd, MAX_RSP_SIZE, "%s", USB_RTS);
+	len = usb_write_with_timeout(handle->cmd, strlen(handle->cmd), CON_TIMEOUT);
+	if (len > 0) {
+
+		/* receive CTS */
+		memset(handle->cmd, 0, MAX_RSP_SIZE);
+		len = usb_read_with_timeout(handle->cmd, MAX_RSP_SIZE, CON_TIMEOUT);
+		if ((len == (int)strlen(USB_CTS))&&
+		    (!strncmp(handle->cmd, USB_CTS, strlen(USB_CTS)))) {
+
+			/* send DATA */
+			len = usb_write_with_timeout(handle->data, length, CON_TIMEOUT);
+			if (len > 0) {
+
+				/* get FIN */
+				memset(handle->cmd, 0, sizeof(handle->cmd));
+				len = usb_read_with_timeout(handle->cmd, sizeof(handle->cmd), CON_TIMEOUT);
+				if ((len == (int)strlen(USB_FIN)) &&
+				    (!strncmp(handle->cmd, USB_FIN, strlen(USB_FIN)))) {
+					return true;
+				} else {
+					voprintf_error("%s: failed to get FIN.cmd<%p,%d><%x,%x,%x,%x>\n", __func__,
+						handle->cmd, len, handle->cmd[0], handle->cmd[1], handle->cmd[2], handle->cmd[3]);
+				}
+
+			} else {
+				voprintf_error("%s: send DATA error.\n", __func__);
+			}
+		} else {
+			voprintf_error("%s: Not CTS after RTS.cmd<%p,%d><%x,%x,%x,%x>\n", __func__,
+				handle->cmd, len, handle->cmd[0], handle->cmd[1], handle->cmd[2], handle->cmd[3]);
+		}
+	} else {
+		voprintf_error("%s: send RTS error.\n", __func__);
+	}
+	return false;
+}
+
+/* store data in pool (EXSPACE) and write when pool is full */
+static int do_store_or_write(struct mrdump_usb_handle *handle, uint8_t *buf, uint32_t length)
+{
+	int total;
+	unsigned int leftspace, mylen, reval;
+
+
+	/* count for leftspace */
+	total = EXSPACE;
+	leftspace = total - handle->idx;
+
+	/* check length */
+	if (length > leftspace) {
+		mylen = leftspace;
+		reval = length - leftspace;
+	} else {
+		mylen = length;
+		reval = 0;
+	}
+
+	/* store */
+	while (mylen > 0) {
+		handle->data[handle->idx] = *buf;
+		handle->idx++;
+		buf++;
+		mylen--;
+	}
+
+	/* write */
+	if (handle->idx == total) {
+		if (!usb_data_transfer(handle, handle->idx)) {
+			voprintf_error("%s: connection failed.(error idx: %d)\n",
+			__func__, handle->idx);
+			return -1;
+		}
+		handle->idx = 0;
+	}
+
+	return reval;
+}
+
+static int usb_write_cb(void *opaque_handle, void *buf, int size)
+{
+	unsigned int    len, moves;
+	int             ret = 0;
+	uint8_t         *ptr;
+
+	struct mrdump_usb_handle *handle = opaque_handle;
+
+	handle->zipsize += size;
+
+	/* EOF, write the left Data in handle data buffer... */
+	if ((buf == NULL) && (size == 0)) {
+
+		/* MUST: a delay for the last transmission */
+		mdelay(10);
+
+		if (!usb_data_transfer(handle, handle->idx)) {
+			voprintf_error("%s: connection failed.(error idx: %d)\n",
+			__func__, handle->idx);
+			return -1;
+		}
+
+		/* send "MRDUMP END Packet: pattern: MRDUMP08_DONE" */
+		memset((void *)handle->data, 0, sizeof(handle->data));
+		size = snprintf((char *)handle->data, sizeof(handle->data), "MRDUMP08_DONE");
+		if (size < 0) {
+			voprintf_error(" USB Dump: Make MRDUMP END Packet failed.\n");
+			return -1;
+		}
+		if (0 > usb_write_with_timeout(handle->data, strlen((char *)handle->data),
+					       CON_TIMEOUT)) {
+			voprintf_error(" USB Dump: Write MRDUMP END failed.\n");
+			return -1;
+		}
+
+		return 0;
+	}
+
+	/* buf should not be NULL if not EOF */
+	if (buf == NULL)
+		return -1;
+
+	/* process of Store and write */
+	len = size;
+	ptr = (uint8_t *)buf;
+	while (1) {
+		ret = do_store_or_write(handle, ptr, len);
+		if (ret < 0) {
+			voprintf_error(" USB Dump: store and write failed.\n");
+			return -1;
+		} else if (ret == 0) {
+			break;
+		} else {
+			moves = len - ret;
+			ptr += moves;
+			len = ret;
+		}
+	}
+
+	return size;
+}
+
+int mrdump_usb_output(const struct mrdump_control_block *mrdump_cb,
+		      const struct kzip_addlist *memlist,
+		      const struct kzip_addlist *memlist_cmm)
+{
+	int i;
+	struct kzip_addlist expdb_file[2];
+	char *expdb_filename;
+	unsigned int expdb_offset, expdb_filesize;
+	voprintf_info("Output by USB\n");
+
+	struct mrdump_usb_handle *handle = memalign(64, sizeof(struct mrdump_usb_handle));
+	if (handle == NULL) {
+		voprintf_error("No enough memory.");
+		return -1;
+	}
+	memset(handle, 0, sizeof(struct mrdump_usb_handle));
+
+	mdelay(100);
+	bool ok = true;
+	mtk_wdt_restart();
+	struct kzip_file *zf = kzip_open(handle, usb_write_cb);
+	if (zf != NULL) {
+		/* add SYS_COREDUMP */
+		if (!kzip_add_file(zf, memlist, "SYS_COREDUMP"))
+			ok = false;
+		if (ok && !kzip_add_file(zf, memlist_cmm, "kernel.cmm"))
+			ok = false;
+		if (!ok)
+			voprintf_error("failed to generate cmm\n");
+
+		/* add file on expdb */
+		for(i = 0; i < IPANIC_NR_SECTIONS; i++) {
+			if (kedump_get_data_info(i, &expdb_filename, &expdb_offset, &expdb_filesize) == 0) {
+				expdb_file[0].address = expdb_offset;
+				expdb_file[0].size = expdb_filesize;
+				expdb_file[0].type = EXPDB_FILE;
+				expdb_file[0].memmap = 0;
+				expdb_file[0].pageflags = 0;
+				expdb_file[0].struct_page_size = 0;
+				expdb_file[1].address = 0;
+				expdb_file[1].size = 0;
+				expdb_file[1].type = MEM_NO_MAP;
+				expdb_file[1].memmap = 0;
+				expdb_file[1].pageflags = 0;
+				expdb_file[1].struct_page_size = 0;
+				if (!kzip_add_file(zf, expdb_file, expdb_filename))
+					ok = false;
+			}
+		}
+
+		/* close zipfile */
+		kzip_close(zf);
+		usb_write_cb(handle, NULL, 0); /* really write the last part */
+		zf = NULL;
+	} else {
+		ok = false;
+	}
+	free(handle);
+
+	mtk_wdt_restart();
+	if (ok) {
+		mrdump_status_ok("OUTPUT:%s\nMODE:%s\n", "USB DUMP",
+		mrdump_mode2string(mrdump_cb->crash_record.reboot_mode));
+	}
+
+	return ok ? 0 : -1;
+}

+ 690 - 0
app/mt_boot/aee/mrdump_zip.c

@@ -0,0 +1,690 @@
+/* Copyright Statement:
+*
+* This software/firmware and related documentation ("MediaTek Software") are
+* protected under relevant copyright laws. The information contained herein
+* is confidential and proprietary to MediaTek Inc. and/or its licensors.
+* Without the prior written permission of MediaTek inc. and/or its licensors,
+* any reproduction, modification, use or disclosure of MediaTek Software,
+* and information contained herein, in whole or in part, shall be strictly prohibited.
+*/
+/* MediaTek Inc. (C) 2016. All rights reserved.
+*
+* BY OPENING THIS FILE, RECEIVER HEREBY UNEQUIVOCALLY ACKNOWLEDGES AND AGREES
+* THAT THE SOFTWARE/FIRMWARE AND ITS DOCUMENTATIONS ("MEDIATEK SOFTWARE")
+* RECEIVED FROM MEDIATEK AND/OR ITS REPRESENTATIVES ARE PROVIDED TO RECEIVER ON
+* AN "AS-IS" BASIS ONLY. MEDIATEK EXPRESSLY DISCLAIMS ANY AND ALL WARRANTIES,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED WARRANTIES OF
+* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE OR NONINFRINGEMENT.
+* NEITHER DOES MEDIATEK PROVIDE ANY WARRANTY WHATSOEVER WITH RESPECT TO THE
+* SOFTWARE OF ANY THIRD PARTY WHICH MAY BE USED BY, INCORPORATED IN, OR
+* SUPPLIED WITH THE MEDIATEK SOFTWARE, AND RECEIVER AGREES TO LOOK ONLY TO SUCH
+* THIRD PARTY FOR ANY WARRANTY CLAIM RELATING THERETO. RECEIVER EXPRESSLY ACKNOWLEDGES
+* THAT IT IS RECEIVER'S SOLE RESPONSIBILITY TO OBTAIN FROM ANY THIRD PARTY ALL PROPER LICENSES
+* CONTAINED IN MEDIATEK SOFTWARE. MEDIATEK SHALL ALSO NOT BE RESPONSIBLE FOR ANY MEDIATEK
+* SOFTWARE RELEASES MADE TO RECEIVER'S SPECIFICATION OR TO CONFORM TO A PARTICULAR
+* STANDARD OR OPEN FORUM. RECEIVER'S SOLE AND EXCLUSIVE REMEDY AND MEDIATEK'S ENTIRE AND
+* CUMULATIVE LIABILITY WITH RESPECT TO THE MEDIATEK SOFTWARE RELEASED HEREUNDER WILL BE,
+* AT MEDIATEK'S OPTION, TO REVISE OR REPLACE THE MEDIATEK SOFTWARE AT ISSUE,
+* OR REFUND ANY SOFTWARE LICENSE FEES OR SERVICE CHARGE PAID BY RECEIVER TO
+* MEDIATEK FOR SUCH MEDIATEK SOFTWARE AT ISSUE.
+*/
+
+#include <malloc.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <string.h>
+#include <assert.h>
+#include <lib/crc.h>
+#include <lib/zutil.h>
+#include <lib/zlib.h>
+#include "aee.h"
+#include "mrdump_private.h"
+
+#ifdef MTK_3LEVEL_PAGETABLE
+#include <stdlib.h>
+#include <err.h>
+#endif
+
+#define KZIP_DEBUG(x...)
+
+#define KDUMP_SIZE_REPORT 0x1000000
+#define KDUMP_TICK_WDT 0x10000
+
+#ifdef MRDUMP_ZIP_NO_COMPRESSION
+#define KDUMP_ZLIB_LEVEL Z_NO_COMPRESSION
+#else
+#define KDUMP_ZLIB_LEVEL Z_BEST_SPEED
+#endif
+
+#define ZIPVERSION_NEEDED 45UL
+
+static char zero_page[PAGE_SIZE] __attribute__((aligned(PAGE_SIZE))) = {0};
+
+static void putvalue(void* dest, uint64_t x, int nbByte)
+{
+	uint8_t *buf = (uint8_t *)dest;
+	int n;
+	for (n = 0; n < nbByte; n++) {
+		buf[n] = (unsigned char)(x & 0xff);
+		x >>= 8;
+	}
+#if 0
+	if (x != 0) {
+		/* data overflow - hack for ZIP64 */
+		for (n = 0; n < nbByte; n++) {
+			buf[n] = 0xff;
+		}
+	}
+#endif
+}
+
+static int put_zip64_eoc_directory_record(uint8_t *buf, int record_num, uint64_t zip_centralheader_offset, int zip_centralheader_size)
+{
+	uint8_t *oldbuf = buf;
+	putvalue(buf, ZIP64ENDOFCENTRALDIRMAGIC, 4);
+	buf += 4;
+	putvalue(buf, 44, 8); /* zip64 eoc size */
+	buf += 8;
+	putvalue(buf, ZIPVERSION_NEEDED, 2); /* version made by */
+	buf += 2;
+	putvalue(buf, ZIPVERSION_NEEDED, 2); /* version needed to extract */
+	buf += 2;
+	putvalue(buf, 0, 4); /* number of this disk */
+	buf += 4;
+	putvalue(buf, 0, 4); /* number of the disk with the start of the central directory */
+	buf += 4;
+	putvalue(buf, record_num, 8); /* total number of entries in the central directory on this disk */
+	buf += 8;
+	putvalue(buf, record_num, 8); /* total number of entries in the central directory */
+	buf += 8;
+	putvalue(buf, zip_centralheader_size, 8); /* size of the central directory */
+	buf += 8;
+	putvalue(buf, zip_centralheader_offset, 8); /* offset of start of central directory with respect to the starting disk number */
+	buf += 8;
+	return buf - oldbuf;
+}
+
+static int put_zip64_eoc_directory_locator(uint8_t *buf, uint64_t zip64_eoc_offset)
+{
+	uint8_t *oldbuf = buf;
+	putvalue(buf, ZIP64ENDOFCENTRALDIRLOCATORMAGIC, 4);
+	buf += 4;
+	putvalue(buf, 0, 4); /* number of the disk with the start of the zip64 end of central directory */
+	buf += 4;
+	putvalue(buf, zip64_eoc_offset, 8); /* relative offset of the zip64 end of central directory record */
+	buf += 8;
+	putvalue(buf, 1, 4); /* total number of disks */
+	buf += 4;
+	return buf - oldbuf;
+}
+
+static int put_eoc_directory_record(uint8_t *buf, int record_num, uint64_t zip_centralheader_offset, int zip_centralheader_size)
+{
+	uint8_t *oldbuf = buf;
+	putvalue(buf, ENDOFCENTRALDIRMAGIC, 4);
+	buf += 4;
+	putvalue(buf, 0, 2); /* Number of this disk */
+	buf += 2;
+	putvalue(buf, 0, 2); /* Disk where central directory starts */
+	buf += 2;
+	putvalue(buf, record_num, 2); /* Number of central directory records on this disk */
+	buf += 2;
+	putvalue(buf, record_num, 2); /* Total number of central directory records */
+	buf += 2;
+	putvalue(buf, zip_centralheader_size, 4);
+	buf += 4;
+	putvalue(buf, 0xffffffff, 4);
+	buf += 4;
+	putvalue(buf, 0, 2); /* Comment length (n) */
+	buf += 2;
+	return buf - oldbuf;
+}
+
+static int put_localheader(uint8_t *buf, const char *filename, int level)
+{
+	uint8_t *oldbuf = buf;
+	putvalue(buf, LOCALHEADERMAGIC, 4);
+	buf += 4;
+	putvalue(buf, ZIPVERSION_NEEDED, 2);
+	buf += 2;
+
+	uint16_t flag = 0;
+	if ((level==8) || (level == 9))
+		flag |= 2;
+	if ((level == 2))
+		flag |= 4;
+	if ((level == 1))
+		flag |= 6;
+#if 0
+	if (password != NULL)
+		flag |= 1;
+#endif
+
+	putvalue(buf, flag | 0x8, 2);
+	buf += 2;
+
+	putvalue(buf, Z_DEFLATED, 2);
+	buf += 2;
+
+	putvalue(buf,0UL, 4);
+	buf += 4;
+
+	// CRC / Compressed size / Uncompressed size will be filled in later and rewritten later
+	putvalue(buf, 0UL, 4); /* crc 32, unknown */
+	buf += 4;
+	putvalue(buf, 0xFFFFFFFFUL, 4); /* compressed size, unknown */
+	buf += 4;
+	putvalue(buf, 0xFFFFFFFFUL, 4); /* uncompressed size, unknown */
+	buf += 4;
+	putvalue(buf, strlen(filename), 2); /* size of filename */
+	buf += 2;
+	putvalue(buf, 4 + 8 + 8, 2); /* size of extra field */
+	buf += 2;
+
+	memcpy(buf, filename, strlen(filename));
+	buf += strlen(filename);
+
+	/* ZIP64 extension */
+	putvalue(buf, 0x0001, 2); /* ZIP64_EXTENSION */
+	buf += 2;
+	putvalue(buf, 8 + 8, 2);
+	buf += 2;
+	putvalue(buf, 0UL, 8);
+	buf += 8;
+	putvalue(buf, 0UL, 8);
+	buf += 8;
+
+	return buf - oldbuf;
+}
+
+static int put_centralheader(uint8_t *buf, const char *filename, int level, uint64_t zip_localheader_offset, uint64_t size, uint64_t uncomp_size, uint32_t crc32_value)
+{
+	uint8_t *oldbuf = buf;
+
+	putvalue(buf, CENTRALHEADERMAGIC, 4);
+	buf += 4;
+	putvalue(buf, ZIPVERSION_NEEDED, 2);
+	buf += 2;
+	putvalue(buf, ZIPVERSION_NEEDED, 2);
+	buf += 2;
+
+	uint16_t flag = 0;
+	if ((level==8) || (level == 9))
+		flag |= 2;
+	if ((level == 2))
+		flag |= 4;
+	if ((level == 1))
+		flag |= 6;
+#if 0
+	if (password != NULL)
+		flag |= 1;
+#endif
+
+	putvalue(buf, flag | 0x8, 2);
+	buf += 2;
+
+	putvalue(buf, Z_DEFLATED, 2);
+	buf += 2;
+
+	putvalue(buf,0UL, 4);
+	buf += 4;
+
+	// CRC / Compressed size / Uncompressed size will be filled in later and rewritten later
+	putvalue(buf, crc32_value, 4); /* crc 32 */
+	buf += 4;
+	putvalue(buf, 0xffffffffUL, 4); /* compressed size */
+	buf += 4;
+	putvalue(buf, 0xffffffffUL, 4); /* uncompressed size */
+	buf += 4;
+	putvalue(buf, strlen(filename), 2);
+	buf += 2;
+	putvalue(buf, 4 + 8 + 8 + 8, 2); /* size of extra field */
+	buf += 2;
+	putvalue(buf, 0UL, 2); /* size of comment field */
+	buf += 2;
+	putvalue(buf, 0UL, 2); /* disk number */
+	buf += 2;
+	putvalue(buf, 0UL, 2); /* internal attributes */
+	buf += 2;
+	putvalue(buf, 0UL, 4); /* external file attributes */
+	buf += 4;
+	putvalue(buf, 0xffffffffUL, 4); /* Relative offset */
+	buf += 4;
+	memcpy(buf, filename, strlen(filename));
+	buf += strlen(filename);
+
+	/* ZIP64 extension */
+	putvalue(buf, 0x0001, 2); /* ZIP64_EXTENSION */
+	buf += 2;
+	putvalue(buf, 8 + 8 + 8, 2);
+	buf += 2;
+	putvalue(buf, uncomp_size, 8);
+	buf += 8;
+	putvalue(buf, size, 8);
+	buf += 8;
+	putvalue(buf, zip_localheader_offset, 8);
+	buf += 8;
+
+	return buf - oldbuf;
+}
+
+static int kzip_write_current(struct kzip_file *zfile, void *buf, int len)
+{
+	KZIP_DEBUG("%s: write_cb %p len %d\n", __func__, zfile->write_cb, len);
+	int retval = zfile->write_cb(zfile->handle, buf, len);
+	if (retval > 0) {
+		zfile->current_size += retval;
+	}
+	if ((zfile->current_size - zfile->reported_size) >= KDUMP_SIZE_REPORT) {
+		vo_show_progress(zfile->current_size / 0x100000);
+		zfile->reported_size = zfile->current_size;
+	}
+	if ((zfile->current_size - zfile->wdk_kick_size) >= KDUMP_TICK_WDT) {
+		mtk_wdt_restart();
+		zfile->wdk_kick_size = zfile->current_size;
+	}
+	return retval;
+}
+
+struct kzip_file *kzip_open(void *handle, int (*write_cb)(void *handle, void *p, int size))
+{
+	struct kzip_file *zf = malloc(sizeof(struct kzip_file));
+	if (zf == NULL) {
+		KZIP_DEBUG("%s: No enough memory\n", __func__);
+		return NULL;
+	}
+	memset(zf, 0, sizeof(struct kzip_file));
+	zf->handle = handle;
+	zf->write_cb = write_cb;
+	KZIP_DEBUG("%s: handle zf %p %p write_cb %p\n", __func__, zf, zf->handle, zf->write_cb);
+
+	vo_show_progress(0);
+	return zf;
+}
+
+bool kzip_close(struct kzip_file *zf)
+{
+	uint64_t central_header_offset = zf->current_size, zip64_eoc_offset;
+	struct kzip_entry *zentries = zf->zentries;
+	int num = zf->entries_num;
+
+	int i, hsize = 0, local_hsize;
+	uint8_t databuf[128];
+	for (i = 0; i < num; i++) {
+		local_hsize = put_centralheader(databuf, zentries[i].filename, zentries[i].level,
+		                                    zentries[i].localheader_offset,
+		                                    zentries[i].comp_size,
+		                                    zentries[i].uncomp_size,
+		                                    zentries[i].crc32);
+		if (kzip_write_current(zf, databuf, local_hsize) != local_hsize) {
+			goto error;
+		}
+		hsize += local_hsize;
+	}
+	voprintf_debug("%s: current_size %lld hoffset %lld\n", __func__, zf->current_size, central_header_offset);
+
+	zip64_eoc_offset = zf->current_size;
+	local_hsize = put_zip64_eoc_directory_record(databuf, num, central_header_offset, hsize);
+	if ((local_hsize > 0) && (kzip_write_current(zf, databuf, local_hsize) != local_hsize)) {
+		goto error;
+	}
+
+	local_hsize = put_zip64_eoc_directory_locator(databuf, zip64_eoc_offset);
+	if ((local_hsize > 0) && (kzip_write_current(zf, databuf, local_hsize) != local_hsize)) {
+		goto error;
+	}
+
+	local_hsize = put_eoc_directory_record(databuf, num, central_header_offset, hsize);
+	if (kzip_write_current(zf, databuf, local_hsize) != local_hsize) {
+		goto error;
+	}
+	free(zf);
+	return true;
+error:
+	free(zf);
+	return false;
+}
+
+#define CHUNK 65536
+
+/* Compress from file source to file dest until EOF on source.
+   def() returns Z_OK on success, Z_MEM_ERROR if memory could not be
+   allocated for processing, Z_STREAM_ERROR if an invalid compression
+   level is supplied, Z_VERSION_ERROR if the version of zlib.h and the
+   version of the library linked do not match, or Z_ERRNO if there is
+   an error reading or writing the files. */
+
+static bool kzip_add_file_no_mapped(struct kzip_file *zfile, const struct kzip_addlist *memlist,
+                                    int *flush, int *ret, uint8_t *in, uint8_t *out,
+                                    struct kzip_entry *zentry, z_stream *strm, struct aee_timer *zip_time)
+{
+	uint64_t mem_size = memlist->size;
+	uint8_t *memsrc = (uint8_t *)(uintptr_t)memlist->address;
+	*flush = (memlist->size == 0) ? Z_FINISH : Z_NO_FLUSH;
+	voprintf_debug("-- Compress memory %llx, size %llu\n",
+	               memlist->address, memlist->size);
+
+	do {
+		int in_size = mem_size > CHUNK ? CHUNK : mem_size;
+		memcpy(in, memsrc, in_size);
+		zentry->crc32 = crc32_no_comp(zentry->crc32, in, in_size);
+		memsrc += in_size;
+		mem_size -= in_size;
+		strm->avail_in = in_size;
+		strm->next_in = in;
+
+		/* run deflate() on input until output buffer not full, finish
+		   compression if all of source has been read in */
+		do {
+			strm->avail_out = CHUNK;
+			strm->next_out = out;
+			*ret = deflate(strm, *flush);    /* no bad return value */
+			assert(*ret != Z_STREAM_ERROR);  /* state not clobbered */
+			int have = CHUNK - strm->avail_out;
+			if (have > 0) {
+				aee_timer_stop(zip_time);
+				if (kzip_write_current(zfile, out, have) != have) {
+					voprintf_debug("-- Compress memory %llx, error. surplus size: %u\n",
+					               memlist->address, mem_size);
+					return false;
+				}
+				aee_timer_start(zip_time);
+			}
+		} while (strm->avail_out == 0);
+		assert(strm->avail_in == 0);     /* all input will be used */
+
+	} while (mem_size > 0);
+
+	voprintf_debug("-- Compress memory %llx, done. surplus size: %u\n",
+	               memlist->address, mem_size);
+	return true;
+}
+
+#ifndef MTK_3LEVEL_PAGETABLE
+/* full mapping at LK, only one function is needed. kzip_add_file_no_mapped() */
+#define kzip_add_file_do_mapped kzip_add_file_no_mapped
+#else
+/* LPAE, map before accessing the address of memory */
+#define MAX_MAP_CNT (SECTION_SIZE/CHUNK)
+#define mapflags (MMU_MEMORY_TYPE_NORMAL_WRITE_BACK | MMU_MEMORY_AP_P_RW_U_NA)
+extern uint64_t v2p_64(uint64_t vptr);
+long mrdump_mem_map(const struct kzip_addlist *memlist,
+		    uint64_t paddr, vaddr_t vaddr, unsigned long sz, uint64_t zero_pa)
+{
+	uint64_t memmap = memlist->memmap;
+	uint64_t pageflags = memlist->pageflags;
+	uint32_t struct_page_size = memlist->struct_page_size;
+
+	long i, memmap_sz = sz / PAGE_SIZE * struct_page_size, invalid_cnt = 0, offset;
+	vaddr_t page_start;
+	uint64_t pa;
+
+	/* map memmap */
+	memmap += paddr / PAGE_SIZE * struct_page_size;
+	offset = (long)memmap&(PAGE_SIZE - 1);
+	page_start = vaddr + sz + offset; /* page struct map to vaddr + sz!!! */
+	for (i = -offset; i < memmap_sz; i += PAGE_SIZE) {
+		pa = v2p_64(memmap + i);
+		if (pa < DRAM_PHY_ADDR
+		  || arch_mmu_map(pa, page_start + i, mapflags, PAGE_SIZE) != NO_ERROR) {
+			paddr = pa;
+			vaddr = page_start - offset + i;
+			goto fail;
+		}
+	}
+	/* map DDR according memmap flag */
+	for (i = 0; i < memmap_sz; i += struct_page_size, vaddr += PAGE_SIZE, paddr += PAGE_SIZE) {
+		if (*(uint64_t *)(page_start + i)&pageflags) {
+			if (arch_mmu_map(zero_pa, vaddr, mapflags, PAGE_SIZE) == NO_ERROR) {
+				invalid_cnt++;
+				continue;
+			}
+		}
+
+		if (arch_mmu_map(paddr, vaddr, mapflags, PAGE_SIZE) != NO_ERROR)
+			goto fail;
+	}
+	return invalid_cnt;
+fail:
+	voprintf_debug("map error: paddr=0x%016llx, vaddr=0x%08x, zero_pa=0x%016llx\n", paddr, vaddr, zero_pa);
+	return -1;
+}
+
+static bool is_linux_kernel_memory_dump(const struct kzip_addlist *addlist)
+{
+	uint64_t memmap = addlist->memmap;
+	uint64_t pageflags = addlist->pageflags;
+	uint32_t struct_page_size = addlist->struct_page_size;
+
+	char dump_type[32] = {0};
+	if (mrdump_get_env(MRDUMP_DUMP_TYPE, dump_type, sizeof(dump_type))) {
+		return false;
+	}
+	if (strcmp(dump_type, MRDUMP_LINUX_KERNEL_MEMORY) == 0) {
+		if ((memmap > 0) && (pageflags > 0) && (struct_page_size > 0)) {
+			voprintf_debug("dump_linux_kernel_memory = 1, memmap(0x%llx), pageflags(0x%llx), struct_page_size(0x%x)\n",
+					memmap, pageflags, struct_page_size);
+			return true;
+		}
+	}
+	voprintf_debug("dump_linux_kernel_memory = 0, memmap(0x%llx), pageflags(0x%llx), struct_page_size(0x%x)\n",
+			memmap, pageflags, struct_page_size);
+	return false;
+}
+
+static bool kzip_add_file_do_mapped(struct kzip_file *zfile, const struct kzip_addlist *memlist,
+                                    int *flush, int *ret, uint8_t *in, uint8_t *out,
+                                    struct kzip_entry *zentry, z_stream *strm, struct aee_timer *zip_time)
+{
+	/* multiple physical address mapped onto static 2MB address space. (scratch_addr) */
+	int cnt = 0;
+	uint64_t paddr = memlist->address;
+	long invalid_cnt = -1, tot_invalid_cnt = 0;
+	vaddr_t vaddr = ROUNDUP(scratch_addr(), SECTION_SIZE);
+	voprintf_debug("-- map: paddr=0x%016llx, vaddr=0x%08x, zero_page=%p\n", paddr, vaddr, zero_page);
+
+	uint64_t mem_size = memlist->size;
+	uint8_t *memsrc;
+	*flush = (memlist->size == 0) ? Z_FINISH : Z_NO_FLUSH;
+	voprintf_debug("-- Compress memory %llx, size %llu\n", memlist->address, memlist->size);
+
+	bool dump_linux_kernel_memory = is_linux_kernel_memory_dump(memlist);
+
+	do {
+		/* arch_mmu_map by each 2MB size */
+		if (cnt == 0) {
+			if (dump_linux_kernel_memory)
+				invalid_cnt = mrdump_mem_map(memlist, paddr, vaddr, SECTION_SIZE, v2p_64((uint64_t)(uintptr_t)zero_page));
+
+			if (invalid_cnt >= 0) {
+				tot_invalid_cnt += invalid_cnt;
+			} else {
+				int map_ok = arch_mmu_map(paddr, vaddr, mapflags, SECTION_SIZE);
+				if (map_ok != NO_ERROR) {
+					voprintf_debug("-- arch_mmu_map map error: map_ok=%d, paddr=0x%016llx, vaddr=0x%08x\n",
+					               map_ok, paddr, vaddr);
+					return false;
+				}
+			}
+			memsrc = (uint8_t *)vaddr;
+		}
+
+		int in_size = mem_size > CHUNK ? CHUNK : mem_size;
+		memcpy(in, memsrc, in_size);
+		zentry->crc32 = crc32_no_comp(zentry->crc32, in, in_size);
+		memsrc += in_size;
+		mem_size -= in_size;
+		strm->avail_in = in_size;
+		strm->next_in = in;
+
+		/* run deflate() on input until output buffer not full, finish
+		   compression if all of source has been read in */
+		do {
+			strm->avail_out = CHUNK;
+			strm->next_out = out;
+			*ret = deflate(strm, *flush);    /* no bad return value */
+			assert(*ret != Z_STREAM_ERROR);  /* state not clobbered */
+			int have = CHUNK - strm->avail_out;
+			if (have > 0) {
+				aee_timer_stop(zip_time);
+				if (kzip_write_current(zfile, out, have) != have) {
+					voprintf_debug("-- Compress memory %llx, error. surplus size: %u\n",
+					               memlist->address, mem_size);
+					return false;
+				}
+				aee_timer_start(zip_time);
+			}
+		} while (strm->avail_out == 0);
+		assert(strm->avail_in == 0);     /* all input will be used */
+
+		/* mod by 2MB (SECTION_SIZE) */
+		cnt++;
+		cnt %= MAX_MAP_CNT;
+		if (cnt == 0)
+			paddr += SECTION_SIZE;
+
+	} while (mem_size > 0);
+
+	voprintf_debug("-- Compress memory %llx, done. surplus size: %lld, ignore: %dMB\n", memlist->address, mem_size, tot_invalid_cnt * 4 / 1024);
+	return true;
+}
+#endif
+
+static bool kzip_add_file_from_expdb(struct kzip_file *zfile, const struct kzip_addlist *addlist,
+                                    int *flush, int *ret, uint8_t *in, uint8_t *out,
+                                    struct kzip_entry *zentry, z_stream *strm, struct aee_timer *zip_time)
+{
+	uint64_t offset_src = addlist->address;
+	int64_t mem_size = addlist->size;
+
+	*flush = (addlist->size == 0) ? Z_FINISH : Z_NO_FLUSH;
+	voprintf_debug("-- Compress expdb offset %llx, size %llu\n", offset_src, mem_size);
+
+	do {
+		/* read from expdb to memsrc */
+		if (mem_size > CHUNK) {
+			mrdump_read_expdb(in, CHUNK, offset_src);
+		} else {
+			mrdump_read_expdb(in, (int)mem_size, offset_src);
+		}
+
+		int in_size = mem_size > CHUNK ? CHUNK : mem_size;
+		zentry->crc32 = crc32_no_comp(zentry->crc32, in, in_size);
+		mem_size -= in_size;
+		strm->avail_in = in_size;
+		strm->next_in = in;
+
+		/* run deflate() on input until output buffer not full, finish
+		   compression if all of source has been read in */
+		do {
+			strm->avail_out = CHUNK;
+			strm->next_out = out;
+			*ret = deflate(strm, *flush);    /* no bad return value */
+			assert(*ret != Z_STREAM_ERROR);  /* state not clobbered */
+			int have = CHUNK - strm->avail_out;
+			if (have > 0) {
+				aee_timer_stop(zip_time);
+				if (kzip_write_current(zfile, out, have) != have) {
+					voprintf_debug("-- Compress expdb offset %llx, error. surplus size: %u\n",
+					               offset_src, mem_size);
+					return false;
+				}
+				aee_timer_start(zip_time);
+			}
+		} while (strm->avail_out == 0);
+		assert(strm->avail_in == 0);     /* all input will be used */
+
+		offset_src += in_size;
+
+	} while (mem_size > 0);
+
+	voprintf_debug("-- Compress expdb offset %llx, done. surplus size: %u\n", offset_src, mem_size);
+	return true;
+}
+
+bool kzip_add_file(struct kzip_file *zfile, const struct kzip_addlist *addlist, const char *zfilename)
+{
+	int ret, flush;
+	z_stream strm;
+	struct aee_timer zip_time;
+
+	if (zfile->entries_num >= KZIP_ENTRY_MAX) {
+		voprintf_error("Too many zip entry %d\n", zfile->entries_num);
+		return false;
+	}
+
+	voprintf_debug("%s: zf %p(%p) %s\n", __func__, zfile, zfile->write_cb, zfilename);
+	struct kzip_entry *zentry = &zfile->zentries[zfile->entries_num++];
+	zentry->filename = strdup(zfilename);
+	zentry->localheader_offset = zfile->current_size;
+	zentry->level = KDUMP_ZLIB_LEVEL;
+	zentry->crc32 = 0xffffffffUL;
+
+	KZIP_DEBUG("%s: write local header\n", __func__);
+	uint8_t zip_localheader[128];
+	int hsize = put_localheader(zip_localheader, zfilename, zentry->level);
+	if (kzip_write_current(zfile, zip_localheader, hsize) != hsize) {
+		return false;
+	}
+
+	KZIP_DEBUG("%s: init compressor\n", __func__);
+	/* allocate deflate state */
+	memset(&strm, 0, sizeof(z_stream));
+	ret = deflateInit2(&strm, zentry->level, Z_DEFLATED, -MAX_WBITS, DEF_MEM_LEVEL, Z_DEFAULT_STRATEGY);
+	if (ret != Z_OK) {
+		voprintf_error("zlib compress init failed\n");
+		return false;
+	}
+
+	uint64_t start = zfile->current_size, uncomp_size = 0;
+
+	uint8_t *out = malloc(CHUNK);
+	uint8_t *in = malloc(CHUNK);
+	if ((out == NULL) || (in == NULL)) {
+		voprintf_error("%s: malloc failed in %p out %p.\n", __func__, in, out);
+		goto error;
+	}
+
+	aee_timer_init(&zip_time);
+	aee_timer_start(&zip_time);
+	do {
+		switch (addlist->type) {
+			case MEM_NO_MAP:
+				if (kzip_add_file_no_mapped(zfile, addlist, &flush, &ret, in, out, zentry, &strm, &zip_time) == false)
+					goto error;
+				break;
+			case MEM_DO_MAP:
+				if (kzip_add_file_do_mapped(zfile, addlist, &flush, &ret, in, out, zentry, &strm, &zip_time) == false)
+					goto error;
+				break;
+			case EXPDB_FILE:
+				if (kzip_add_file_from_expdb(zfile, addlist, &flush, &ret, in, out, zentry, &strm, &zip_time) == false)
+					goto error;
+				break;
+			default:
+				goto error;
+				break;
+		}
+		uncomp_size += addlist->size;
+		addlist++;
+		/* done when last data in file processed */
+	} while (flush != Z_FINISH);
+	assert(ret == Z_STREAM_END);        /* stream will be complete */
+	aee_timer_stop(&zip_time);
+	voprintf_info("Zip time: %d sec\n", zip_time.acc_ms / 1000);
+
+	zentry->comp_size = zfile->current_size - start;
+	zentry->uncomp_size = uncomp_size;
+	zentry->crc32 = zentry->crc32 ^ 0xffffffffUL;
+
+	deflateEnd(&strm);
+	free(out);
+	free(in);
+	return true;
+
+error:
+	free(out);
+	free(in);
+	deflateEnd(&strm);
+	return false;
+}

+ 319 - 0
app/mt_boot/aee/platform_debug.c

@@ -0,0 +1,319 @@
+/* Copyright Statement:
+*
+* This software/firmware and related documentation ("MediaTek Software") are
+* protected under relevant copyright laws. The information contained herein
+* is confidential and proprietary to MediaTek Inc. and/or its licensors.
+* Without the prior written permission of MediaTek inc. and/or its licensors,
+* any reproduction, modification, use or disclosure of MediaTek Software,
+* and information contained herein, in whole or in part, shall be strictly prohibited.
+*/
+/* MediaTek Inc. (C) 2016. All rights reserved.
+*
+* BY OPENING THIS FILE, RECEIVER HEREBY UNEQUIVOCALLY ACKNOWLEDGES AND AGREES
+* THAT THE SOFTWARE/FIRMWARE AND ITS DOCUMENTATIONS ("MEDIATEK SOFTWARE")
+* RECEIVED FROM MEDIATEK AND/OR ITS REPRESENTATIVES ARE PROVIDED TO RECEIVER ON
+* AN "AS-IS" BASIS ONLY. MEDIATEK EXPRESSLY DISCLAIMS ANY AND ALL WARRANTIES,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED WARRANTIES OF
+* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE OR NONINFRINGEMENT.
+* NEITHER DOES MEDIATEK PROVIDE ANY WARRANTY WHATSOEVER WITH RESPECT TO THE
+* SOFTWARE OF ANY THIRD PARTY WHICH MAY BE USED BY, INCORPORATED IN, OR
+* SUPPLIED WITH THE MEDIATEK SOFTWARE, AND RECEIVER AGREES TO LOOK ONLY TO SUCH
+* THIRD PARTY FOR ANY WARRANTY CLAIM RELATING THERETO. RECEIVER EXPRESSLY ACKNOWLEDGES
+* THAT IT IS RECEIVER'S SOLE RESPONSIBILITY TO OBTAIN FROM ANY THIRD PARTY ALL PROPER LICENSES
+* CONTAINED IN MEDIATEK SOFTWARE. MEDIATEK SHALL ALSO NOT BE RESPONSIBLE FOR ANY MEDIATEK
+* SOFTWARE RELEASES MADE TO RECEIVER'S SPECIFICATION OR TO CONFORM TO A PARTICULAR
+* STANDARD OR OPEN FORUM. RECEIVER'S SOLE AND EXCLUSIVE REMEDY AND MEDIATEK'S ENTIRE AND
+* CUMULATIVE LIABILITY WITH RESPECT TO THE MEDIATEK SOFTWARE RELEASED HEREUNDER WILL BE,
+* AT MEDIATEK'S OPTION, TO REVISE OR REPLACE THE MEDIATEK SOFTWARE AT ISSUE,
+* OR REFUND ANY SOFTWARE LICENSE FEES OR SERVICE CHARGE PAID BY RECEIVER TO
+* MEDIATEK FOR SUCH MEDIATEK SOFTWARE AT ISSUE.
+*/
+#include <stdlib.h>
+#include <dev/aee_platform_debug.h>
+#ifdef MTK_GPT_SCHEME_SUPPORT
+#include <platform/partition.h>
+#else
+#include <mt_partition.h>
+#endif
+#include <printf.h>
+#include <arch/arm/mmu.h>
+#include <platform/plat_atf_dbg_info.h>
+#include <part_interface.h>
+#ifdef MICROTRUST_TEE_DUMP_SUPPORT
+#include <plat_teei_dbg_info.h>
+#endif
+
+unsigned int (* plat_dfd20_get)(u64 offset, int *len, CALLBACK dev_write) = NULL;
+unsigned int (* plat_dram_get)(u64 offset, int *len, CALLBACK dev_write) = NULL;
+unsigned int (* plat_cpu_bus_get)(u64 offset, int *len, CALLBACK dev_write) = NULL;
+unsigned int (* plat_spm_data_get)(u64 offset, int *len, CALLBACK dev_write) = NULL;
+unsigned int (* plat_spm_sram_data_get)(u64 offset, int *len, CALLBACK dev_write) = NULL;
+unsigned int (* plat_atf_log_get)(u64 offset, int *len, CALLBACK dev_write) = NULL;
+unsigned int (* plat_atf_crash_get)(u64 offset, int *len, CALLBACK dev_write) = NULL;
+unsigned int (* plat_atf_raw_log_get)(u64 offset, int *len, CALLBACK dev_write) = NULL;
+unsigned int (* plat_atf_rdump_get)(u64 offset, int *len, CALLBACK dev_write) = NULL;
+unsigned int (* plat_atf_footprint_log_get)(u64 offset, int *len, CALLBACK dev_write) = NULL;
+unsigned int (* plat_hvfs_get)(u64 offset, int *len, CALLBACK dev_write) = NULL;
+#ifdef MTK_TINYSYS_SSPM_SUPPORT
+unsigned int (* plat_sspm_coredump_get)(u64 offset, int *len, CALLBACK dev_write) = NULL;
+unsigned int (* plat_sspm_data_get)(u64 offset, int *len, CALLBACK dev_write) = NULL;
+unsigned int (* plat_sspm_xfile_get)(u64 offset, int *len, CALLBACK dev_write) = NULL;
+unsigned int (* plat_sspm_log_get)(u64 offset, int *len, CALLBACK dev_write) = NULL;
+#endif
+unsigned int (* plat_pllk_last_log_get)(u64 offset, int *len, CALLBACK dev_write) = NULL;
+unsigned int (* plat_dur_lkdump_get)(u64 offset, int *len, CALLBACK dev_write) = NULL;
+unsigned int (* plat_mcdi_get)(u64 offset, int *len, CALLBACK dev_write) = NULL;
+#ifdef MTK_TINYSYS_SCP_SUPPORT
+unsigned int (* plat_scp_coredump_get)(u64 offset, int *len, CALLBACK dev_write) = NULL;
+#endif
+unsigned int (* plat_infra_cg_get)(u64 offset, int *len, CALLBACK dev_write) = NULL;
+#ifdef MTK_AUDIODSP_SUPPORT
+unsigned int (* plat_adsp_coredump_get)(u64 offset, int *len, CALLBACK dev_write) = NULL;
+#endif
+#ifdef MTK_TINYSYS_MCUPM_SUPPORT
+unsigned int (* plat_mcupm_coredump_get)(u64 offset, int *len, CALLBACK dev_write) = NULL;
+unsigned int (* plat_mcupm_data_get)(u64 offset, int *len, CALLBACK dev_write) = NULL;
+unsigned int (* plat_mcupm_xfile_get)(u64 offset, int *len, CALLBACK dev_write) = NULL;
+unsigned int (* plat_mcupm_log_get)(u64 offset, int *len, CALLBACK dev_write) = NULL;
+#endif
+#ifdef MTK_PICACHU_SUPPORT
+unsigned int (* plat_picachu_log_get)(u64 offset, int *len, CALLBACK dev_write) = NULL;
+#endif
+#ifdef MICROTRUST_TEE_DUMP_SUPPORT
+unsigned int (* plat_teei_log_get)(u64 offset, int *len, CALLBACK dev_write) = NULL;
+#endif
+#ifdef MTK_DPM_SUPPORT
+unsigned int (* plat_dpm_data_get)(u64 offset, int *len, CALLBACK dev_write) = NULL;
+#endif
+#ifdef MTK_GPU_DFD_SUPPORT
+unsigned int (* plat_gpu_dfd_get)(u64 offset, int *len, CALLBACK dev_write) = NULL;
+#endif
+
+/* in case that platform didn't support platform_debug_init() */
+int platform_debug_init(void) __attribute__((weak));
+int platform_debug_init(void)
+{
+	return 0;
+}
+
+int lkdump_debug_init(void)
+{
+	if (g_boot_arg->boot_mode != DOWNLOAD_BOOT)
+		atf_log_init();
+
+#ifdef MICROTRUST_TEE_DUMP_SUPPORT
+	if (g_boot_arg->boot_mode != DOWNLOAD_BOOT)
+		teei_log_init();
+#endif
+
+	return platform_debug_init();
+}
+
+/* function pointer should be set after platform_debug_init() */
+unsigned int kedump_plat_savelog(int condition, u64 offset, int *len, CALLBACK dev_write)
+{
+	switch (condition) {
+		case AEE_PLAT_DFD20:
+			return (!plat_dfd20_get ? 0 : plat_dfd20_get(offset, len, dev_write));
+		case AEE_PLAT_DRAM:
+			return (!plat_dram_get ? 0 : plat_dram_get(offset, len, dev_write));
+		case AEE_PLAT_CPU_BUS:
+			return (!plat_cpu_bus_get ? 0 : plat_cpu_bus_get(offset, len, dev_write));
+		case AEE_PLAT_SPM_DATA:
+			return (!plat_spm_data_get ? 0 : plat_spm_data_get(offset, len, dev_write));
+		case AEE_PLAT_SPM_SRAM_DATA:
+                        return (!plat_spm_sram_data_get ? 0 : plat_spm_sram_data_get(offset, len, dev_write));
+		case AEE_PLAT_ATF_LAST_LOG:
+			return (!plat_atf_log_get ? 0 : plat_atf_log_get(offset, len, dev_write));
+		case AEE_PLAT_ATF_CRASH_REPORT:
+			return (!plat_atf_crash_get ? 0 : plat_atf_crash_get(offset, len, dev_write));
+		case AEE_PLAT_ATF_RAW_LOG:
+			return (!plat_atf_raw_log_get ? 0 : plat_atf_raw_log_get(offset, len, dev_write));
+		case AEE_PLAT_ATF_RDUMP_LOG:
+			return (!plat_atf_rdump_get ? 0 : plat_atf_rdump_get(offset, len, dev_write));
+		case AEE_PLAT_ATF_FOOTPRINT_LOG:
+			return (!plat_atf_footprint_log_get ? 0 : plat_atf_footprint_log_get(offset, len, dev_write));
+		case AEE_PLAT_HVFS:
+			return (!plat_hvfs_get ? 0 : plat_hvfs_get(offset, len, dev_write));
+#ifdef MTK_TINYSYS_SSPM_SUPPORT
+		case AEE_PLAT_SSPM_COREDUMP:
+			return (!plat_sspm_coredump_get ? 0 : plat_sspm_coredump_get(offset, len, dev_write));
+		case AEE_PLAT_SSPM_DATA:
+			return (!plat_sspm_data_get ? 0 : plat_sspm_data_get(offset, len, dev_write));
+		case AEE_PLAT_SSPM_XFILE:
+			return (!plat_sspm_xfile_get ? 0 : plat_sspm_xfile_get(offset, len, dev_write));
+		case AEE_PLAT_SSPM_LAST_LOG:
+			return (!plat_sspm_log_get ? 0 : plat_sspm_log_get(offset, len, dev_write));
+#endif
+		case AEE_PLAT_PLLK_LAST_LOG:
+			return (!plat_pllk_last_log_get ? 0 : plat_pllk_last_log_get(offset, len, dev_write));
+		case AEE_PLAT_LOG_DUR_LKDUMP:
+			return (!plat_dur_lkdump_get ? 0 : plat_dur_lkdump_get(offset, len, dev_write));
+		case AEE_PLAT_MCDI_DATA:
+			return (!plat_mcdi_get ? 0 : plat_mcdi_get(offset, len, dev_write));
+#ifdef MTK_TINYSYS_SCP_SUPPORT
+		case AEE_PLAT_SCP_COREDUMP:
+			return (!plat_scp_coredump_get ? 0 : plat_scp_coredump_get(offset, len, dev_write));
+#endif
+		case AEE_PLAT_INFRA_CG:
+			return (!plat_infra_cg_get ? 0 : plat_infra_cg_get(offset, len, dev_write));
+#ifdef MTK_AUDIODSP_SUPPORT
+		case AEE_PLAT_ADSP_COREDUMP:
+			return (!plat_adsp_coredump_get ? 0 : plat_adsp_coredump_get(offset, len, dev_write));
+#endif
+#ifdef MTK_PICACHU_SUPPORT
+		case AEE_PLAT_PICACHU_LOG:
+			return (!plat_picachu_log_get ? 0 : plat_picachu_log_get(offset, len, dev_write));
+#endif
+#ifdef MICROTRUST_TEE_DUMP_SUPPORT
+		case AEE_PLAT_TEEI_LOG:
+			return (!plat_teei_log_get ? 0 : plat_teei_log_get(offset, len, dev_write));
+#endif
+#ifdef MTK_TINYSYS_MCUPM_SUPPORT
+		case AEE_PLAT_MCUPM_COREDUMP:
+			return (!plat_mcupm_coredump_get ? 0 : plat_mcupm_coredump_get(offset, len, dev_write));
+		case AEE_PLAT_MCUPM_DATA:
+			return (!plat_mcupm_data_get ? 0 : plat_mcupm_data_get(offset, len, dev_write));
+		case AEE_PLAT_MCUPM_XFILE:
+			return (!plat_mcupm_xfile_get ? 0 : plat_mcupm_xfile_get(offset, len, dev_write));
+		case AEE_PLAT_MCUPM_LAST_LOG:
+			return (!plat_mcupm_log_get ? 0 : plat_mcupm_log_get(offset, len, dev_write));
+#endif
+#ifdef MTK_DPM_SUPPORT
+		case AEE_PLAT_DPM_DATA:
+			return (!plat_dpm_data_get ? 0 : plat_dpm_data_get(offset, len, dev_write));
+#endif
+#ifdef MTK_GPU_DFD_SUPPORT
+		case AEE_PLAT_GPU_DFD:
+			return (!plat_gpu_dfd_get ? 0 : plat_gpu_dfd_get(offset, len, dev_write));
+#endif
+
+		default:
+			break;
+	}
+	return 0;
+}
+
+void mrdump_write_log(u64 offset_dst, void *data, int len)
+{
+	dprintf(CRITICAL, "%s: Enter\n", __func__);
+
+	if ((offset_dst > MRDUMP_EXPDB_DRAM_KLOG_OFFSET) || (offset_dst < MRDUMP_EXPDB_BOTTOM_OFFSET)) {
+		dprintf(CRITICAL, "%s: access not permitted. offset(0x%llx).\n", __func__, offset_dst);
+		return;
+	}
+
+	if ((offset_dst - len) < MRDUMP_EXPDB_BOTTOM_OFFSET) {
+		dprintf(CRITICAL, "%s: log size(0x%x) too big.\n", __func__, len);
+		return;
+	}
+
+	int index = partition_get_index("expdb");
+	part_dev_t *dev = mt_part_get_device();
+	if (index == -1 || dev == NULL) {
+		dprintf(CRITICAL, "%s: no %s partition[%d]\n", __func__, "expdb", index);
+		return;
+	}
+#if defined(MTK_NEW_COMBO_EMMC_SUPPORT)  || defined(MTK_TLC_NAND_SUPPORT) || defined(MTK_MLC_NAND_SUPPORT) || defined(MTK_UFS_SUPPORT)
+	int part_id = partition_get_region(index);
+#endif
+	u64 part_size = partition_get_size(index);
+	if (part_size < offset_dst) {
+		dprintf(CRITICAL, "%s: partition size(%llx) is less then reserved (%llx)\n", __func__, part_size, offset_dst);
+		return;
+	}
+	u64 part_offset = partition_get_offset(index) + part_size - offset_dst;
+
+	dprintf(CRITICAL, "%s: offset %lld size %lld\n", __func__, part_offset, part_size);
+
+#if defined(MTK_EMMC_SUPPORT) || defined(MTK_UFS_SUPPORT)
+#if defined(MTK_NEW_COMBO_EMMC_SUPPORT) || defined(MTK_UFS_SUPPORT)
+	dev->write(dev, (uchar *)data, part_offset, len, part_id);
+#else
+	dev->write(dev, (uchar *)data, part_offset, len);
+#endif
+#else
+	dev->write(dev, (uchar *)data, part_offset, len, part_id);
+#endif
+}
+
+void mrdump_read_log(void *data, int len, u64 offset_src)
+{
+	dprintf(CRITICAL, "%s: Enter\n", __func__);
+
+	if ((offset_src > MRDUMP_EXPDB_DRAM_KLOG_OFFSET) || (offset_src < MRDUMP_EXPDB_BOTTOM_OFFSET)) {
+		dprintf(CRITICAL, "%s: access not permitted. offset(0x%llx).\n", __func__, offset_src);
+		return;
+	}
+
+	if ((offset_src - len) < MRDUMP_EXPDB_BOTTOM_OFFSET) {
+		dprintf(CRITICAL, "%s: log size(0x%x) too big.\n", __func__, len);
+		return;
+	}
+
+	int index = partition_get_index("expdb");
+	part_dev_t *dev = mt_part_get_device();
+	if (index == -1 || dev == NULL) {
+		dprintf(CRITICAL, "%s: no %s partition[%d]\n", __func__, "expdb", index);
+		return;
+	}
+#if defined(MTK_NEW_COMBO_EMMC_SUPPORT) || defined(MTK_TLC_NAND_SUPPORT) || defined(MTK_MLC_NAND_SUPPORT) || defined(MTK_UFS_SUPPORT)
+	int part_id = partition_get_region(index);
+#endif
+	u64 part_size = partition_get_size(index);
+	if (part_size < offset_src) {
+		dprintf(CRITICAL, "%s: partition size(%llx) is less then reserved (%llx)\n", __func__, part_size, offset_src);
+		return;
+	}
+	u64 part_offset = partition_get_offset(index) + part_size - offset_src;
+
+	dprintf(CRITICAL, "%s: offset %lld size %lld\n", __func__, part_offset, part_size);
+
+#if defined(MTK_EMMC_SUPPORT) || defined(MTK_UFS_SUPPORT)
+#if defined(MTK_NEW_COMBO_EMMC_SUPPORT) || defined(MTK_UFS_SUPPORT)
+	dev->read(dev, part_offset, (uchar *)data, len, part_id);
+#else
+	dev->read(dev, part_offset, (uchar *)data, len);
+#endif
+#else
+	dev->read(dev, part_offset, (uchar *)data, len, part_id);
+#endif
+}
+
+void mrdump_read_expdb(void *data, int len, u64 offset_src)
+{
+	dprintf(CRITICAL, "%s: Enter\n", __func__);
+
+	int index = partition_get_index("expdb");
+	part_dev_t *dev = mt_part_get_device();
+	if (index == -1 || dev == NULL) {
+		dprintf(CRITICAL, "%s: no %s partition[%d]\n", __func__, "expdb", index);
+		return;
+	}
+#if defined(MTK_NEW_COMBO_EMMC_SUPPORT) || defined(MTK_TLC_NAND_SUPPORT) || defined(MTK_MLC_NAND_SUPPORT) || defined(MTK_UFS_SUPPORT)
+	int part_id = partition_get_region(index);
+#endif
+	u64 part_size = partition_get_size(index);
+	if (part_size < offset_src) {
+		dprintf(CRITICAL, "%s: partition size(%llx) is less then reserved (%llx)\n", __func__, part_size, offset_src);
+		return;
+	}
+	if ((offset_src + len) > (part_size - MRDUMP_EXPDB_DRAM_KLOG_OFFSET)) {
+		dprintf(CRITICAL, "%s: log size(0x%x) too big.\n", __func__, len);
+		return;
+	}
+	u64 part_offset = partition_get_offset(index) + offset_src;
+
+	dprintf(CRITICAL, "%s: offset %lld size %lld\n", __func__, part_offset, part_size);
+
+#if defined(MTK_EMMC_SUPPORT) || defined(MTK_UFS_SUPPORT)
+#if defined(MTK_NEW_COMBO_EMMC_SUPPORT) || defined(MTK_UFS_SUPPORT)
+	dev->read(dev, part_offset, (uchar *)data, len, part_id);
+#else
+	dev->read(dev, part_offset, (uchar *)data, len);
+#endif
+#else
+	dev->read(dev, part_offset, (uchar *)data, len, part_id);
+#endif
+}
+

+ 594 - 0
app/mt_boot/aee/ram_console.c

@@ -0,0 +1,594 @@
+/* Copyright Statement:
+*
+* This software/firmware and related documentation ("MediaTek Software") are
+* protected under relevant copyright laws. The information contained herein
+* is confidential and proprietary to MediaTek Inc. and/or its licensors.
+* Without the prior written permission of MediaTek inc. and/or its licensors,
+* any reproduction, modification, use or disclosure of MediaTek Software,
+* and information contained herein, in whole or in part, shall be strictly prohibited.
+*/
+/* MediaTek Inc. (C) 2016. All rights reserved.
+*
+* BY OPENING THIS FILE, RECEIVER HEREBY UNEQUIVOCALLY ACKNOWLEDGES AND AGREES
+* THAT THE SOFTWARE/FIRMWARE AND ITS DOCUMENTATIONS ("MEDIATEK SOFTWARE")
+* RECEIVED FROM MEDIATEK AND/OR ITS REPRESENTATIVES ARE PROVIDED TO RECEIVER ON
+* AN "AS-IS" BASIS ONLY. MEDIATEK EXPRESSLY DISCLAIMS ANY AND ALL WARRANTIES,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED WARRANTIES OF
+* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE OR NONINFRINGEMENT.
+* NEITHER DOES MEDIATEK PROVIDE ANY WARRANTY WHATSOEVER WITH RESPECT TO THE
+* SOFTWARE OF ANY THIRD PARTY WHICH MAY BE USED BY, INCORPORATED IN, OR
+* SUPPLIED WITH THE MEDIATEK SOFTWARE, AND RECEIVER AGREES TO LOOK ONLY TO SUCH
+* THIRD PARTY FOR ANY WARRANTY CLAIM RELATING THERETO. RECEIVER EXPRESSLY ACKNOWLEDGES
+* THAT IT IS RECEIVER'S SOLE RESPONSIBILITY TO OBTAIN FROM ANY THIRD PARTY ALL PROPER LICENSES
+* CONTAINED IN MEDIATEK SOFTWARE. MEDIATEK SHALL ALSO NOT BE RESPONSIBLE FOR ANY MEDIATEK
+* SOFTWARE RELEASES MADE TO RECEIVER'S SPECIFICATION OR TO CONFORM TO A PARTICULAR
+* STANDARD OR OPEN FORUM. RECEIVER'S SOLE AND EXCLUSIVE REMEDY AND MEDIATEK'S ENTIRE AND
+* CUMULATIVE LIABILITY WITH RESPECT TO THE MEDIATEK SOFTWARE RELEASED HEREUNDER WILL BE,
+* AT MEDIATEK'S OPTION, TO REVISE OR REPLACE THE MEDIATEK SOFTWARE AT ISSUE,
+* OR REFUND ANY SOFTWARE LICENSE FEES OR SERVICE CHARGE PAID BY RECEIVER TO
+* MEDIATEK FOR SUCH MEDIATEK SOFTWARE AT ISSUE.
+*/
+
+#include <stdio.h>
+#include <stdlib.h>		// for ALIGN()
+#include <string.h>
+#include <arch/arm/mmu.h>
+#include <platform/boot_mode.h>
+#include <platform/ram_console.h>
+#include <libfdt.h>
+
+#define RAM_CONSOLE_SIG (0x43474244) /* DBGC */
+#define MOD "RAM_CONSOLE"
+
+struct ram_console_buffer {
+	u32 sig;
+	/* for size comptible */
+	u32 off_pl;
+	u32 off_lpl; /* last preloader */
+	u32 sz_pl;
+	u32 off_lk;
+	u32 off_llk; /* last lk */
+	u32 sz_lk;
+	u32 padding[2]; /* size = 2 * 16 = 32 byte */
+	u32 dump_step;
+	u32 sz_buffer;
+	u32 off_linux;
+	u32 off_console;
+	u32 padding2[3];
+};
+
+#define RAM_CONSOLE_LK_SIZE 16
+struct reboot_reason_lk {
+	u32 last_func[RAM_CONSOLE_LK_SIZE];
+};
+
+struct reboot_reason_pl {
+	u32 wdt_status;
+	u32 last_func[0];
+};
+
+struct reboot_reason_kernel {
+	u32 fiq_step;
+	/* 0xaeedeadX: X=1 (HWT), X=2 (KE), X=3 (nested panic) */
+	/* details see enum AEE_EXP_TYPE_NUM in ram_console_common.h */
+	u32 exp_type;
+	u32 others[0];
+};
+
+enum CUR_BOOT_TYPE {
+	BOOT_NORMAL = 0,
+	BOOT_ABNORMAL,
+	BOOT_INVALID
+};
+
+static int cur_boot = BOOT_INVALID;
+
+extern int sLOG(char *fmt, ...);
+#define LOG(fmt, ...)           \
+    do { \
+        sLOG(fmt, ##__VA_ARGS__);       \
+        printf(fmt, ##__VA_ARGS__); \
+    } while(0)
+
+static struct ram_console_buffer *ram_console = NULL;
+static uint32_t ram_console_size;
+extern BOOT_ARGUMENT *g_boot_arg;
+
+static void ram_console_fatal(const char *str)
+{
+	LOG("%s. FATAL:%s\n", MOD, str);
+	while(1)
+		;
+}
+
+static void ram_console_memory_info_valid(struct ram_console_memory_info *memory_info)
+{
+	if (memory_info->magic1 != MEM_MAGIC1 || memory_info->magic2 != MEM_MAGIC2) {
+		LOG("%s. passed arg magic:[0x%x, 0x%x] mismatch\n", MOD, memory_info->magic1, memory_info->magic2);
+		ram_console_fatal("illegal magic number");
+	}
+}
+
+static void ram_console_atag_valid(void)
+{
+	u32 sram_addr;
+	u32 sram_size;
+	u32 def_type;
+	u32 memory_info_offset;
+
+	if (g_boot_arg != NULL) {
+		sram_addr = g_boot_arg->ram_console_sram_addr;
+		sram_size = g_boot_arg->ram_console_sram_size;
+		def_type = g_boot_arg->ram_console_def_type;
+		memory_info_offset = g_boot_arg->ram_console_memory_info_offset;
+		if (def_type != RAM_CONSOLE_DEF_SRAM && def_type != RAM_CONSOLE_DEF_DRAM)
+			ram_console_fatal("unknown def type");
+		if (sram_addr == 0 || sram_size == 0)
+			ram_console_fatal("sram addr size zero");
+		if (memory_info_offset <= sram_size)
+			ram_console_fatal("memory offset invalid value");
+	} else {
+		ram_console_fatal("unexpected g_boot_arg null pointer");
+	}
+}
+
+static struct ram_console_memory_info *ram_console_atag_memory_info(void)
+{
+	u32 sram_addr;
+	u32 memory_info_offset;
+	struct ram_console_memory_info *memory_info = NULL;
+
+	ram_console_atag_valid();
+
+	sram_addr = g_boot_arg->ram_console_sram_addr;
+	memory_info_offset = g_boot_arg->ram_console_memory_info_offset;
+	memory_info = (struct ram_console_memory_info *)(sram_addr + memory_info_offset);
+	ram_console_memory_info_valid(memory_info);
+	return memory_info;
+}
+
+extern bool cmdline_append(const char *append_string);
+static void ram_console_ptr_init_by_atag(void)
+{
+	struct ram_console_memory_info *memory_info = NULL;
+	u32 sram_addr;
+	u32 sram_size;
+	u32 def_type;
+	u32 memory_info_offset;
+	char cmd_buf[256];
+
+	if (g_boot_arg == NULL)
+		ram_console_fatal("unexpected g_boot_arg null pointer");
+
+	sram_addr = g_boot_arg->ram_console_sram_addr;
+	sram_size = g_boot_arg->ram_console_sram_size;
+	def_type = g_boot_arg->ram_console_def_type;
+	memory_info_offset = g_boot_arg->ram_console_memory_info_offset;
+	LOG("%s. boot_arg(PL2LK): sram_addr:0x%x, sram_size:0x%x, def_type:0x%x, memory_info_offset:0x%x\n", MOD, sram_addr, sram_size, def_type, memory_info_offset);
+
+	memory_info = ram_console_atag_memory_info();
+
+	if (def_type == RAM_CONSOLE_DEF_SRAM) {
+		ram_console = (struct ram_console_buffer *)sram_addr;
+		ram_console_size = sram_size;
+	} else if (def_type == RAM_CONSOLE_DEF_DRAM) {
+		ram_console = (struct ram_console_buffer *)memory_info->dram_addr;
+		ram_console_size = memory_info->dram_size;
+#ifdef MTK_3LEVEL_PAGETABLE
+	{
+		uint32_t start = (uint32_t)ram_console;
+		arch_mmu_map(ROUNDDOWN((uint64_t)start, PAGE_SIZE), ROUNDDOWN((uint32_t)start, PAGE_SIZE),
+		             MMU_MEMORY_TYPE_NORMAL_WRITE_BACK | MMU_MEMORY_AP_P_RW_U_NA, ROUNDUP(ram_console_size, PAGE_SIZE));
+	}
+#endif
+	} else {
+		ram_console_fatal("unknown def type");
+	}
+
+	if (ram_console->sig != RAM_CONSOLE_SIG) {
+		LOG("%s. %s(0x%x) sig %x mismatch\n", MOD, (def_type == RAM_CONSOLE_DEF_SRAM) ? "sram" : "dram", (unsigned int)ram_console, ram_console->sig);
+		ram_console_fatal("sig mismatch");
+	}
+
+	memset(cmd_buf, 0x0, sizeof(cmd_buf));
+	snprintf(cmd_buf, 256,
+		"ramoops.mem_address=0x%x ramoops.mem_size=0x%x ramoops.pmsg_size=0x%x ramoops.console_size=0x%x",
+		memory_info->pstore_addr, memory_info->pstore_size,
+		memory_info->pstore_pmsg_size, memory_info->pstore_console_size);
+	cmdline_append(cmd_buf);
+}
+
+void ram_console_init(void)
+{
+	int i;
+	struct reboot_reason_lk *rr_lk;
+	ram_console_ptr_init_by_atag();
+
+	if (ram_console) {
+		LOG("%s. start: %p, size: 0x%x\n", MOD, ram_console, ram_console_size);
+	} else {
+		LOG("%s. sig not match\n", MOD);
+		return;
+	}
+
+	ram_console->off_lk = ram_console->off_lpl + ALIGN(ram_console->sz_pl, 64);
+	ram_console->off_llk = ram_console->off_lk + ALIGN(sizeof(struct reboot_reason_lk), 64);
+	ram_console->sz_lk = sizeof(struct reboot_reason_lk);
+	if (ram_console->sz_lk == sizeof(struct reboot_reason_lk) && (ram_console->off_lk + ram_console->sz_lk == ram_console->off_llk)) {
+		LOG("%s. lk last status: ", MOD);
+		rr_lk = (void*)ram_console + ram_console->off_lk;
+		for (i = 0; i < RAM_CONSOLE_LK_SIZE; i++) {
+			LOG("0x%x ", rr_lk->last_func[i]);
+		}
+		LOG("\n");
+		memcpy((void*)ram_console + ram_console->off_llk, (void*)ram_console + ram_console->off_lk, ram_console->sz_lk);
+	} else {
+		LOG("%s. lk size mismatch %x + %x != %x\n", MOD, ram_console->sz_lk, ram_console->off_lk, ram_console->off_llk);
+		ram_console->sz_lk = sizeof(struct reboot_reason_lk);
+	}
+	ram_console->off_linux = ram_console->off_llk + ALIGN(ram_console->sz_lk, 64);
+}
+
+
+#define RE_BOOT_BY_WDT_SW 2
+#define RE_BOOT_NORMAL_BOOT 0
+#define RE_BOOT_BY_EINT 256/*we can find the definition from preloader ,this value should  sync with preloader incase issue happened*/
+#define RE_BOOT_BY_SYSRST 512/*we can find the definition from preloader ,this value should  sync with preloader incase issue happened*/
+
+#ifdef MTK_PMIC_FULL_RESET
+#define RE_BOOT_FULL_PMIC 0x800
+#endif
+
+#define U_VAR(type) rc_##type
+static unsigned int U_VAR(wdt_status), U_VAR(fiq_step), U_VAR(exp_type);
+static bool U_VAR(set_flag) = false;
+
+bool ram_console_reboot_by_mrdump_key(void)
+{
+	unsigned int wdt_status;
+	wdt_status = ((struct reboot_reason_pl*)((void*)ram_console + ram_console->off_pl))->wdt_status;
+	return ((wdt_status & RE_BOOT_BY_EINT)|(wdt_status & RE_BOOT_BY_SYSRST))?true:false;
+}
+
+#ifdef MTK_PMIC_FULL_RESET
+bool ram_console_reboot_by_cold_reset(void)
+{
+	unsigned int wdt_status;
+	wdt_status = ((struct reboot_reason_pl*)((void*)ram_console + ram_console->off_pl))->wdt_status;
+	return (wdt_status & RE_BOOT_FULL_PMIC) ? true : false;
+}
+#endif
+
+bool ram_console_get_wdt_status(unsigned int *wdt_status)
+{
+	if (wdt_status && U_VAR(set_flag)) {
+		*wdt_status = U_VAR(wdt_status);
+		return true;
+	}
+	return false;
+}
+
+bool ram_console_get_fiq_step(unsigned int *fiq_step)
+{
+	if (fiq_step && U_VAR(set_flag)) {
+		*fiq_step = U_VAR(fiq_step);
+		return true;
+	}
+	return false;
+}
+
+bool ram_console_get_exp_type(unsigned int *exp_type)
+{
+	if (exp_type && U_VAR(set_flag)) {
+		*exp_type = U_VAR(exp_type);
+		return true;
+	}
+	return false;
+}
+
+bool ram_console_set_exp_type(unsigned int exp_type)
+{
+	bool ret = false;
+	if (ram_console && ram_console->off_linux &&
+		(ram_console->off_linux == (ram_console->off_llk + ALIGN(ram_console->sz_lk, 64))) &&
+		(ram_console->off_pl == sizeof(struct ram_console_buffer))) {
+		if (exp_type < 16) {
+			exp_type = exp_type ^ RAM_CONSOLE_EXP_TYPE_MAGIC;
+			((struct reboot_reason_kernel*)((void*)ram_console + ram_console->off_linux))->exp_type = exp_type;
+			ret = true;
+		} else {
+			LOG("%s. set exp type failed: off_linux:0x%x, off_llk:0x%x, off_pl:0x%x, exp type:%d\n", MOD, ram_console->off_linux, ram_console->off_llk, ram_console->off_pl, exp_type);
+		}
+	}
+	return ret;
+}
+
+/*
+ * struct last_reboot_reason is defined at [kernel/drivers/misc/mediatek/ram_console/mtk_ram_console.c]
+ * if you need to access struct members in LK, this struct must be sync-ed with kernel code.
+ */
+struct last_reboot_reason {
+	uint32_t fiq_step;
+	/* 0xaeedeadX: X=1 (HWT), X=2 (KE), X=3 (nested panic) */
+	uint32_t exp_type;
+	uint64_t kaslr_offset;
+	uint64_t ram_console_buffer_addr;
+};
+static struct last_reboot_reason* krbr;
+
+bool ram_console_get_kaslr_offset(uint64_t* kaslr_offset)
+{
+	if (krbr && U_VAR(set_flag)) {
+		if (krbr->kaslr_offset == 0xecab1e) {
+			*kaslr_offset = 0;
+			return false;
+		}
+
+		if (krbr->kaslr_offset == 0xd15ab1e) {
+			*kaslr_offset = 0;
+		} else {
+			*kaslr_offset = krbr->kaslr_offset;
+		}
+		return true;
+	}
+	return false;
+}
+
+bool ram_console_is_abnormal_boot(void)
+{
+	unsigned int fiq_step, wdt_status, exp_type;
+	int reinit_flag = 0;
+
+	if (!ram_console) {
+		ram_console_ptr_init_by_atag();
+		reinit_flag = 1;
+	}
+	if (ram_console && ram_console->off_linux &&
+		(ram_console->off_linux == (ram_console->off_llk + ALIGN(ram_console->sz_lk, 64))) &&
+		(ram_console->off_pl == sizeof(struct ram_console_buffer))) {
+		wdt_status = ((struct reboot_reason_pl*)((void*)ram_console + ram_console->off_pl))->wdt_status;
+		krbr = ((struct last_reboot_reason*)((void*)ram_console + ram_console->off_linux));
+		fiq_step = ((struct reboot_reason_kernel*)((void*)ram_console + ram_console->off_linux))->fiq_step;
+		exp_type = ((struct reboot_reason_kernel*)((void*)ram_console + ram_console->off_linux))->exp_type;
+		LOG("%s. wdt_status 0x%x, fiq_step 0x%x, exp_type 0x%x\n", MOD, wdt_status, fiq_step, RAM_CONSOLE_EXP_TYPE_DEC(exp_type));
+		if (fiq_step != 0 && (exp_type ^ RAM_CONSOLE_EXP_TYPE_MAGIC) >= 16) {
+			fiq_step = 0;
+			((struct reboot_reason_kernel*)((void*)ram_console + ram_console->off_linux))->fiq_step = fiq_step;
+		}
+		U_VAR(wdt_status) = wdt_status;
+		U_VAR(fiq_step) = fiq_step;
+		U_VAR(exp_type) = RAM_CONSOLE_EXP_TYPE_DEC(exp_type);
+		U_VAR(set_flag) = true;
+		LOG("%s. set reboot reason info done\n", MOD);
+#ifdef MTK_PMIC_FULL_RESET
+		if ((fiq_step == 0 && (wdt_status == RE_BOOT_BY_WDT_SW || wdt_status == RE_BOOT_FULL_PMIC)) || (wdt_status == RE_BOOT_NORMAL_BOOT))
+#else
+		if ((fiq_step == 0 && wdt_status == RE_BOOT_BY_WDT_SW) || (wdt_status == RE_BOOT_NORMAL_BOOT))
+#endif
+			return false;
+		else
+			return true;
+	} else {
+		if (ram_console) {
+			LOG("%s. set reboot reason info failed: off_linux:0x%x, off_llk:0x%x, off_pl:0x%x, reinit flag:%d\n", MOD, ram_console->off_linux, ram_console->off_llk, ram_console->off_pl, reinit_flag);
+		} else {
+			LOG("%s. ram console buffer NULL\n", MOD);
+		}
+	}
+	return false;
+}
+
+/*
+ * The return value of ram_console_is_abnoraml_boot() maybe changed if
+ * ram_console was restored by kedump_restore_mem(). So we recored the value
+ * in cur_boot before ram_console restored.
+ * The current_is_abnormal_boot() would return the value of cur_boot.
+ */
+int current_is_abnormal_boot(void)
+{
+	if (cur_boot == BOOT_NORMAL || cur_boot == BOOT_ABNORMAL)
+		return cur_boot;
+
+	cur_boot = ram_console_is_abnormal_boot() ? BOOT_ABNORMAL : BOOT_NORMAL;
+
+	return cur_boot;
+}
+
+bool ram_console_should_restore(struct ram_console_buffer *tmp_ram_console)
+{
+	unsigned int fiq_step, wdt_status, exp_type;
+
+	if (cur_boot != BOOT_NORMAL && cur_boot != BOOT_ABNORMAL)
+		cur_boot = ram_console_is_abnormal_boot() ? BOOT_ABNORMAL : BOOT_NORMAL;
+
+	if (U_VAR(set_flag) && tmp_ram_console && tmp_ram_console->off_linux &&
+		(tmp_ram_console->off_linux == (tmp_ram_console->off_llk + ALIGN(tmp_ram_console->sz_lk, 64))) &&
+		(tmp_ram_console->off_pl == sizeof(struct ram_console_buffer))) {
+		wdt_status = ((struct reboot_reason_pl*)((void*)tmp_ram_console + tmp_ram_console->off_pl))->wdt_status;
+		fiq_step = ((struct reboot_reason_kernel*)((void*)tmp_ram_console + tmp_ram_console->off_linux))->fiq_step;
+		exp_type = RAM_CONSOLE_EXP_TYPE_DEC(((struct reboot_reason_kernel *)((void *)tmp_ram_console + tmp_ram_console->off_linux))->exp_type);
+
+		if ((wdt_status != 0 && wdt_status != U_VAR(wdt_status)) ||
+			(fiq_step != 0 && fiq_step != U_VAR(fiq_step)) ||
+			(exp_type != 0 && exp_type != U_VAR(exp_type))) {
+			return true;
+		}
+	}
+	return false;
+}
+
+void ram_console_lk_save(unsigned int val, int index)
+{
+	struct reboot_reason_lk *rr_lk;
+	if (ram_console && ram_console->off_lk < ram_console_size) {
+		rr_lk = (void*)ram_console + ram_console->off_lk;
+		if (index < RAM_CONSOLE_LK_SIZE)
+			rr_lk->last_func[index] = val;
+	}
+}
+
+/* default can be either sram or dram */
+void ram_console_addr_size(unsigned int *addr, unsigned int *size)
+{
+	if (addr == NULL || size == NULL) {
+		LOG("%s. get ram console default info args invalid\n", MOD);
+		return;
+	}
+
+	*addr = (unsigned int)ram_console;
+	*size = ram_console_size;
+}
+
+void ram_console_sram_addr_size(unsigned int *addr, unsigned int *size)
+{
+	if (addr == NULL || size == NULL) {
+		LOG("%s. get ram console sram info args invalid\n", MOD);
+		return;
+	}
+
+	ram_console_atag_valid();
+	*addr = g_boot_arg->ram_console_sram_addr;
+	*size = g_boot_arg->ram_console_sram_size;
+}
+
+u32 ram_console_def_memory(void)
+{
+	ram_console_atag_valid();
+	return g_boot_arg->ram_console_def_type;
+}
+
+u32 ram_console_sram_offset(void)
+{
+	ram_console_atag_valid();
+	return g_boot_arg->ram_console_memory_info_offset;
+}
+
+void sram_plat_dbg_info_addr_size(unsigned int *addr, unsigned int *size)
+{
+	struct ram_console_memory_info *memory_info = NULL;
+
+	if (addr == NULL || size == NULL) {
+		LOG("%s. get plat dbg info args invalid\n", MOD);
+		return;
+	}
+
+	memory_info = ram_console_atag_memory_info();
+	*addr = memory_info->sram_plat_dbg_info_addr;
+	*size = memory_info->sram_plat_dbg_info_size;
+}
+
+void sram_log_store_addr_size(unsigned int *addr, unsigned int *size)
+{
+	struct ram_console_memory_info *memory_info = NULL;
+
+	if (addr == NULL || size == NULL) {
+		LOG("%s. get log_store info args invalid\n", MOD);
+		return;
+	}
+
+	memory_info = ram_console_atag_memory_info();
+	*addr = memory_info->sram_log_store_addr;
+	*size = memory_info->sram_log_store_size;
+}
+
+void sram_mrdump_addr_size(unsigned int *addr, unsigned int *size)
+{
+	struct ram_console_memory_info *memory_info = NULL;
+
+	if (addr == NULL || size == NULL) {
+		LOG("%s. get mrdump info args invalid\n", MOD);
+		return;
+	}
+
+	memory_info = ram_console_atag_memory_info();
+	*addr = memory_info->mrdump_addr;
+	*size = memory_info->mrdump_size;
+}
+
+void pstore_addr_size(unsigned int *addr, unsigned int *size)
+{
+	struct ram_console_memory_info *memory_info = NULL;
+
+	if (addr == NULL || size == NULL) {
+		LOG("%s. get pstore info args invalid\n", MOD);
+		return;
+	}
+
+	memory_info = ram_console_atag_memory_info();
+	*addr = memory_info->pstore_addr;
+	*size = memory_info->pstore_size;
+}
+
+void mrdump_mini_header_addr_size(unsigned int *addr, unsigned int *size)
+{
+	struct ram_console_memory_info *memory_info = NULL;
+
+	if (addr == NULL || size == NULL) {
+		LOG("%s. get minirdump header info args invalid\n", MOD);
+		return;
+	}
+
+	memory_info = ram_console_atag_memory_info();
+	*addr = memory_info->mrdump_mini_header_addr;
+	*size = memory_info->mrdump_mini_header_size;
+}
+
+void ram_console_dts_written(void *fdt)
+{
+	unsigned int addr = 0;
+	unsigned int size = 0;
+	unsigned int def_type = 0;
+	unsigned int memory_info_offset = 0;
+	unsigned int *ptemp;
+	unsigned int buf[4];
+	int offset;
+	int ret;
+
+	offset = fdt_path_offset(fdt, "/chosen");
+	if (offset < 0) {
+		LOG("%s. get /chosen offset failed(%d)\n", MOD, offset);
+		ram_console_fatal("get /chosen offset failed");
+		return;
+	}
+	ptemp = (unsigned int *)buf;
+
+	ram_console_sram_addr_size(&addr, &size);
+	*ptemp = addr;
+	*(ptemp + 1) = size;
+	def_type = ram_console_def_memory();
+	*(ptemp + 2) = def_type;
+	memory_info_offset = ram_console_sram_offset();
+	*(ptemp + 3) = memory_info_offset;
+	LOG("%s. [0x%x,0x%x,0x%x,0x%x]\n", MOD, *ptemp, *(ptemp + 1),
+		*(ptemp + 2), *(ptemp + 3));
+	ret = fdt_setprop(fdt, offset, "ram_console", buf, (4 * sizeof(*ptemp)));
+	if (ret)
+		ram_console_fatal("dts written failed");
+
+	sram_log_store_addr_size(&addr, &size);
+	*ptemp = addr;
+	*(ptemp + 1) = size;
+	LOG("%s. log_store [0x%x,0x%x]\n", MOD, *ptemp, *(ptemp + 1));
+	ret = fdt_setprop(fdt, offset, "log_store", buf, (2 * sizeof(*ptemp)));
+	if (ret)
+		ram_console_fatal("log_store dts written failed");
+
+}
+
+void ram_console_set_dump_step(unsigned int step)
+{
+	if (ram_console) {
+		ram_console->dump_step = step;
+	}
+}
+
+int ram_console_get_dump_step()
+{
+	if (ram_console)
+		return ram_console->dump_step;
+	else {
+		LOG("%s. ram_console not ready\n", MOD);
+		return 0;
+	}
+}
+

+ 63 - 0
app/mt_boot/aee/reboot_record.c

@@ -0,0 +1,63 @@
+#include <string.h>
+#include <arch/ops.h>
+#include <dev/mrdump.h>
+#include <debug.h>
+#include "aee.h"
+#include "mrdump_private.h"
+
+struct mrdump_control_block *mrdump_cb_addr(void)
+{
+	/* directly return the address of debug service on SRAM */
+	return (struct mrdump_control_block *)MRDUMP_CB_ADDR;
+}
+
+int mrdump_cb_size(void)
+{
+	return MRDUMP_CB_SIZE;
+}
+
+int aee_mrdump_get_info(struct mrdump_control_block *mcb)
+{
+	if (mcb == NULL)
+		return -1;
+
+	struct mrdump_control_block *bufp = NULL;
+
+	memset(mcb, 0, sizeof(struct mrdump_control_block));
+
+	bufp = mrdump_cb_addr();
+	if (bufp == NULL)
+		return -2;
+
+	if (memcmp(bufp->sig, MRDUMP_GO_DUMP, 8) == 0) {
+		memcpy(mcb, bufp, sizeof(struct mrdump_control_block));
+		return 0;
+	} else {
+		return -3;
+	}
+}
+
+struct mrdump_control_block *aee_mrdump_get_params(void)
+{
+	struct mrdump_control_block *bufp = mrdump_cb_addr();
+	if (bufp == NULL) {
+		dprintf(CRITICAL, "mrdump_cb is NULL\n");
+		return NULL;
+	}
+	if (memcmp(bufp->sig, MRDUMP_GO_DUMP, 8) == 0) {
+		bufp->sig[0] = 'X';
+		aee_mrdump_flush_cblock(bufp);
+		dprintf(CRITICAL, "Boot record found at %p[%02x%02x]\n", bufp, bufp->sig[0], bufp->sig[1]);
+		return bufp;
+	} else {
+		dprintf(CRITICAL, "No Boot record found\n");
+		return NULL;
+	}
+}
+
+void aee_mrdump_flush_cblock(struct mrdump_control_block *bufp)
+{
+	if (bufp != NULL) {
+		arch_clean_cache_range((addr_t)bufp, sizeof(struct mrdump_control_block));
+	}
+}

+ 370 - 0
app/mt_boot/blockheader.c

@@ -0,0 +1,370 @@
+/* Copyright Statement:
+*
+* This software/firmware and related documentation ("MediaTek Software") are
+* protected under relevant copyright laws. The information contained herein
+* is confidential and proprietary to MediaTek Inc. and/or its licensors.
+* Without the prior written permission of MediaTek inc. and/or its licensors,
+* any reproduction, modification, use or disclosure of MediaTek Software,
+* and information contained herein, in whole or in part, shall be strictly prohibited.
+*/
+/* MediaTek Inc. (C) 2015. All rights reserved.
+*
+* BY OPENING THIS FILE, RECEIVER HEREBY UNEQUIVOCALLY ACKNOWLEDGES AND AGREES
+* THAT THE SOFTWARE/FIRMWARE AND ITS DOCUMENTATIONS ("MEDIATEK SOFTWARE")
+* RECEIVED FROM MEDIATEK AND/OR ITS REPRESENTATIVES ARE PROVIDED TO RECEIVER ON
+* AN "AS-IS" BASIS ONLY. MEDIATEK EXPRESSLY DISCLAIMS ANY AND ALL WARRANTIES,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED WARRANTIES OF
+* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE OR NONINFRINGEMENT.
+* NEITHER DOES MEDIATEK PROVIDE ANY WARRANTY WHATSOEVER WITH RESPECT TO THE
+* SOFTWARE OF ANY THIRD PARTY WHICH MAY BE USED BY, INCORPORATED IN, OR
+* SUPPLIED WITH THE MEDIATEK SOFTWARE, AND RECEIVER AGREES TO LOOK ONLY TO SUCH
+* THIRD PARTY FOR ANY WARRANTY CLAIM RELATING THERETO. RECEIVER EXPRESSLY ACKNOWLEDGES
+* THAT IT IS RECEIVER'S SOLE RESPONSIBILITY TO OBTAIN FROM ANY THIRD PARTY ALL PROPER LICENSES
+* CONTAINED IN MEDIATEK SOFTWARE. MEDIATEK SHALL ALSO NOT BE RESPONSIBLE FOR ANY MEDIATEK
+* SOFTWARE RELEASES MADE TO RECEIVER'S SPECIFICATION OR TO CONFORM TO A PARTICULAR
+* STANDARD OR OPEN FORUM. RECEIVER'S SOLE AND EXCLUSIVE REMEDY AND MEDIATEK'S ENTIRE AND
+* CUMULATIVE LIABILITY WITH RESPECT TO THE MEDIATEK SOFTWARE RELEASED HEREUNDER WILL BE,
+* AT MEDIATEK'S OPTION, TO REVISE OR REPLACE THE MEDIATEK SOFTWARE AT ISSUE,
+* OR REFUND ANY SOFTWARE LICENSE FEES OR SERVICE CHARGE PAID BY RECEIVER TO
+* MEDIATEK FOR SUCH MEDIATEK SOFTWARE AT ISSUE.
+*/
+
+#include "blockheader.h"
+#include <string.h>
+#include <ufs_aio_hcd.h>
+#include <block_generic_interface.h>
+#include "part_dev.h"
+
+#define ID_NUM1   (12)
+#define ID_NUM2   (8)
+#define MAX_BL_NUM   (8)
+
+#define SDMMC_HEADER_VERSION    (1)
+#define SDMMC_HEADER_SIZE       (0x200)
+
+#define HEADER_SIZE_UFS	    UFS_BLOCK_SIZE
+#define HEADER_SIZE_SDMMC   SDMMC_HEADER_SIZE
+
+#define BLOCK_FILL_VALUE        (0x00)
+#define EXTERNAL_HEADER_FILL_VALUE  (0xFF)
+
+// For preloader header
+#define MAGIC_VER                         (0x014D4D4D)
+#define BRLYT_ID                          ("BRLYT")
+#define BRLYT_VER                         (1)
+#define BL_EXIT_MAGIC                     (0x42424242)
+
+#define EXT_PRELOADER_MT6582   0x8A000000
+
+
+
+typedef enum {
+	GFH_FILE_INFO = 0
+	,GFH_BL_INFO
+} GFH_TYPE;
+
+typedef struct {
+	unsigned int magic;
+	unsigned short size;
+	unsigned short type;
+} GFH_Header, *PGFH_Header;
+
+typedef struct {
+	GFH_Header m_gfh_hdr;
+	char id[ID_NUM1];
+	unsigned int file_version;
+	unsigned short file_type;
+	char flash_dev;
+	char sig_type;
+	unsigned int load_addr;
+	unsigned int length;
+	unsigned int max_size;
+	unsigned int content_offset;
+	unsigned int sig_length;
+	unsigned int jump_offset;
+	unsigned int addr;
+} GFH_FILE_INFO_V1, *PGFH_FILE_INFO_V1;
+
+typedef struct {
+	GFH_Header m_gfh_hdr;
+	unsigned int m_bl_attr;
+} GFH_BL_INFO_V1, *PGFH_BL_INFO_V1;
+
+typedef struct {
+	unsigned int   magic;
+	char    dev;
+	unsigned short   type;
+	unsigned int   begin_dev_addr;
+	unsigned int   boundary_dev_addr;
+	unsigned int   attribute;
+} BLDescriptor, PBLDescriptor;
+
+
+// For header block, first 0x200 bytes.
+typedef struct {
+	char id[ID_NUM1];
+	unsigned int version;
+	unsigned int record_region_size;
+} SDMMC_HEADER;
+
+// For header block, second 0x200 bytes.
+typedef struct {
+	char id[ID_NUM2];
+	unsigned int version;
+	unsigned int boot_region_dev_addr;
+	unsigned int main_region_dev_addr;
+	BLDescriptor descriptor[MAX_BL_NUM];
+} MtkBRLayout;
+
+
+unsigned int handle_layout_header(char* data, unsigned int sz, char* cache);
+unsigned int handle_preloader_gfh(PGFH_Header gfh_hdr, MtkBRLayout* mtk_layout);
+unsigned int handle_preloader_ext_gfh(PGFH_Header gfh_hdr, MtkBRLayout* mtk_layout);
+
+/*
+block header layout
+============================== offset: 0x000
+SDMMC_HEADER
+
+============================== offset: 0x200
+MtkBRLayout #1
+
+MtkBRLayout #2
+
+MtkBRLayout #3
+
+....
+
+....
+
+MtkBRLayout #8
+============================== offset: HEADER_BLOCK_SIZE
+*/
+int process_preloader (char* data, /*IN OUT*/unsigned int* psz)
+{
+	char* cache = data + 0x1000000; // offset 16M for buffer.
+	part_dev_t *dev;
+	char header_id[ID_NUM1] = { '\0' };
+	int header_blksz;
+
+	dev = mt_part_get_device();
+
+	if (dev->blkdev->type == BOOTDEV_SDMMC) {
+		strncpy (header_id, HEADER_IDENTIFIER_EMMC, ID_NUM1);
+		header_blksz = HEADER_BLOCK_SIZE_EMMC;
+	} else if (dev->blkdev->type == BOOTDEV_UFS) {
+		strncpy (header_id, HEADER_IDENTIFIER_UFS, ID_NUM1);
+		header_blksz = HEADER_BLOCK_SIZE_UFS;
+	} else {
+		strncpy (header_id, HEADER_IDENTIFIER_NAND, ID_NUM1);
+		header_blksz = HEADER_BLOCK_SIZE_NAND;
+	}
+
+	PGFH_Header gfh_hdr = (PGFH_Header)data;
+	if (MAGIC_VER != gfh_hdr->magic) {
+		return -1;
+	}
+
+	memset(cache, 0xFF, header_blksz/2);
+	memset(cache + header_blksz/2, 0x00, header_blksz/2);
+
+	SDMMC_HEADER* mmcHdr = (SDMMC_HEADER*)cache;
+	memset(mmcHdr, 0, sizeof(SDMMC_HEADER));
+
+	memcpy(mmcHdr->id, header_id, strlen(header_id));
+	mmcHdr->version = SDMMC_HEADER_VERSION;
+
+	if (dev->blkdev->type == BOOTDEV_UFS)
+		mmcHdr->record_region_size = HEADER_SIZE_UFS;
+	else
+		mmcHdr->record_region_size = HEADER_SIZE_SDMMC;
+	memcpy(cache+header_blksz, data, *psz);
+
+	*psz = handle_layout_header(data, *psz, cache);
+
+	memcpy(data, cache, *psz);
+
+	return 0;
+}
+
+/*
+  Check if preloader image is preloader_xxx.bin via header
+*/
+int is_preloader_bin_format(char* data)
+{
+	PGFH_Header gfh_hdr = (PGFH_Header)data;
+
+	//preloader_xxx.bin contains the MAGIC_VER in the begining of header
+	if (MAGIC_VER == gfh_hdr->magic) {
+		return 1;
+	}
+
+	return 0;
+}
+
+/*data: orign data
+sz: data size
+cache: new data cache. will fill data in it.
+return :length: new data length.
+*/
+unsigned int handle_layout_header(char* data, unsigned int sz, char* cache)
+{
+	unsigned int preloader_max_size = 0;
+	char* ext_file_ptr = 0;
+	unsigned int ext_file_length = 0;
+	bool has_ext_file = false;
+	unsigned length = 0;
+	bool do_detect_ext_file = true;
+	part_dev_t *dev;
+	int header_blksz;
+
+	MtkBRLayout* mtk_layout = (MtkBRLayout*)(cache + SDMMC_HEADER_SIZE);
+	memset(mtk_layout, 0, sizeof(MtkBRLayout));
+
+	dev = mt_part_get_device();
+
+	if (dev->blkdev->type == BOOTDEV_SDMMC)
+		header_blksz = HEADER_BLOCK_SIZE_EMMC;
+	else if (dev->blkdev->type == BOOTDEV_UFS)
+		header_blksz = HEADER_BLOCK_SIZE_UFS;
+	else
+		header_blksz = HEADER_BLOCK_SIZE_NAND;
+
+	memcpy(mtk_layout->id, BRLYT_ID, strlen(BRLYT_ID));
+	mtk_layout->version = BRLYT_VER;
+	mtk_layout->boot_region_dev_addr = header_blksz;
+
+	PGFH_Header gfh_hdr = (PGFH_Header)data;
+
+	//Scan preloader info.
+	//will have more than one GFH_Header.
+	preloader_max_size = handle_preloader_gfh(gfh_hdr, mtk_layout);
+
+	//need re-locate.
+	mtk_layout->main_region_dev_addr = mtk_layout->descriptor[0].boundary_dev_addr;
+
+	memset(cache+sz+header_blksz, 0xFF, preloader_max_size-sz); //fill 0xFF between gap.
+	length += (preloader_max_size - header_blksz);
+
+	if (do_detect_ext_file) {
+		//=========process ROM(EXT) File=========
+		// ROM FILE(or EXT) is at the end of preloader, so we scan for it.
+		//(if this block is exist, copy this block after preloader).
+
+		//process rom file will access data behide this pointer.
+		//now gfh_hdr point to preloader mid data.
+		for (; (unsigned int)gfh_hdr < (unsigned int)(data+sz); gfh_hdr=(PGFH_Header)((char*)gfh_hdr+4)) { //scan to file end.
+			if (gfh_hdr->magic == MAGIC_VER
+			        && gfh_hdr->size == sizeof(GFH_FILE_INFO_V1)
+			        && gfh_hdr->type == GFH_FILE_INFO) {
+				PGFH_FILE_INFO_V1 gfh_file_info_v1 = (PGFH_FILE_INFO_V1)gfh_hdr;
+
+				//ROM file maybe have more than 1 ROM blocks.
+				if (EXT_PRELOADER_MT6582 == gfh_file_info_v1->file_version) {
+					has_ext_file = true;
+					ext_file_ptr = (char*)gfh_hdr;
+					ext_file_length = handle_preloader_ext_gfh(gfh_hdr, mtk_layout);
+
+					//final re-locate.
+					mtk_layout->main_region_dev_addr = mtk_layout->descriptor[1].boundary_dev_addr;
+					break;
+				}//end if
+			}
+		}//end for
+		if (has_ext_file) {
+			memcpy(cache+header_blksz+preloader_max_size, ext_file_ptr, ext_file_length);
+			length += ext_file_length;
+		}
+	}
+	return length;
+}
+
+unsigned int handle_preloader_gfh(PGFH_Header gfh_hdr, MtkBRLayout* mtk_layout)
+{
+	PGFH_FILE_INFO_V1 gfh_file_info_v1;
+	PGFH_BL_INFO_V1 gfh_bl_info_v1;
+	unsigned int preloader_max_size = 0;
+	part_dev_t *dev;
+	int header_blksz;
+
+	dev = mt_part_get_device();
+
+	if (dev->blkdev->type == BOOTDEV_SDMMC)
+		header_blksz = HEADER_BLOCK_SIZE_EMMC;
+	else if (dev->blkdev->type == BOOTDEV_UFS)
+		header_blksz = HEADER_BLOCK_SIZE_UFS;
+	else
+		header_blksz = HEADER_BLOCK_SIZE_NAND;
+
+	//will have more than one GFH_Header.
+	while (MAGIC_VER == gfh_hdr->magic) {
+		switch (gfh_hdr->type) {
+			case GFH_FILE_INFO:
+				gfh_file_info_v1 = (PGFH_FILE_INFO_V1)gfh_hdr;
+
+				mtk_layout->descriptor[0].magic           = BL_EXIT_MAGIC;
+				mtk_layout->descriptor[0].dev                   = gfh_file_info_v1->flash_dev;
+				mtk_layout->descriptor[0].type                  = gfh_file_info_v1->file_type;
+				mtk_layout->descriptor[0].begin_dev_addr        = header_blksz;
+				mtk_layout->descriptor[0].boundary_dev_addr     = mtk_layout->descriptor[0].begin_dev_addr + gfh_file_info_v1->max_size;
+				preloader_max_size = gfh_file_info_v1->max_size;
+				//move next Header.
+				gfh_hdr = (PGFH_Header)((char*)gfh_hdr + sizeof(GFH_FILE_INFO_V1));
+				break;
+
+			case GFH_BL_INFO:
+				gfh_bl_info_v1 = (PGFH_BL_INFO_V1)gfh_hdr;
+				mtk_layout->descriptor[0].attribute = gfh_bl_info_v1->m_bl_attr;
+				//move next Header.
+				gfh_hdr = (PGFH_Header)((char*)gfh_hdr + sizeof(GFH_BL_INFO_V1));
+				break;
+
+			default:
+				gfh_hdr = (PGFH_Header)((char*)gfh_hdr + sizeof(GFH_Header));
+				break;
+		}
+	}
+
+	return preloader_max_size;
+}
+
+unsigned int handle_preloader_ext_gfh(PGFH_Header gfh_hdr, MtkBRLayout* mtk_layout)
+{
+	PGFH_FILE_INFO_V1 gfh_file_info_v1;
+	PGFH_BL_INFO_V1 gfh_bl_info_v1;
+	unsigned int ext_file_length = 0;
+
+	while (MAGIC_VER == gfh_hdr->magic) {
+		switch (gfh_hdr->type) {
+			case GFH_FILE_INFO:
+				gfh_file_info_v1 = (PGFH_FILE_INFO_V1)gfh_hdr;
+				mtk_layout->descriptor[1].magic           = BL_EXIT_MAGIC;
+				mtk_layout->descriptor[1].dev                   = mtk_layout->descriptor[0].dev;
+				mtk_layout->descriptor[1].type                  = gfh_file_info_v1->file_type;
+				mtk_layout->descriptor[1].begin_dev_addr        = mtk_layout->descriptor[0].boundary_dev_addr;
+				mtk_layout->descriptor[1].boundary_dev_addr     = mtk_layout->descriptor[1].begin_dev_addr + gfh_file_info_v1->max_size;
+				ext_file_length = gfh_file_info_v1->length;
+				//ext_file_max_size = gfh_file_info_v1->max_size;
+				//move next Header.
+				gfh_hdr = (PGFH_Header)((char*)gfh_hdr + sizeof(GFH_FILE_INFO_V1));
+				break;
+
+			case GFH_BL_INFO:
+				gfh_bl_info_v1 = (PGFH_BL_INFO_V1)gfh_hdr;
+				mtk_layout->descriptor[1].attribute = gfh_bl_info_v1->m_bl_attr;
+				//move next Header.
+				gfh_hdr = (PGFH_Header)((char*)gfh_hdr + sizeof(GFH_BL_INFO_V1));
+				break;
+
+			default:
+				gfh_hdr = (PGFH_Header)((char*)gfh_hdr + sizeof(GFH_Header));
+				break;
+		}
+	}//end while
+
+	return ext_file_length;
+}
+
+
+
+

+ 61 - 0
app/mt_boot/blockheader.h

@@ -0,0 +1,61 @@
+/* Copyright Statement:
+ *
+ * This software/firmware and related documentation ("MediaTek Software") are
+ * protected under relevant copyright laws. The information contained herein
+ * is confidential and proprietary to MediaTek Inc. and/or its licensors.
+ * Without the prior written permission of MediaTek inc. and/or its licensors,
+ * any reproduction, modification, use or disclosure of MediaTek Software,
+ * and information contained herein, in whole or in part, shall be strictly prohibited.
+ */
+/* MediaTek Inc. (C) 2015. All rights reserved.
+ *
+ * BY OPENING THIS FILE, RECEIVER HEREBY UNEQUIVOCALLY ACKNOWLEDGES AND AGREES
+ * THAT THE SOFTWARE/FIRMWARE AND ITS DOCUMENTATIONS ("MEDIATEK SOFTWARE")
+ * RECEIVED FROM MEDIATEK AND/OR ITS REPRESENTATIVES ARE PROVIDED TO RECEIVER ON
+ * AN "AS-IS" BASIS ONLY. MEDIATEK EXPRESSLY DISCLAIMS ANY AND ALL WARRANTIES,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE OR NONINFRINGEMENT.
+ * NEITHER DOES MEDIATEK PROVIDE ANY WARRANTY WHATSOEVER WITH RESPECT TO THE
+ * SOFTWARE OF ANY THIRD PARTY WHICH MAY BE USED BY, INCORPORATED IN, OR
+ * SUPPLIED WITH THE MEDIATEK SOFTWARE, AND RECEIVER AGREES TO LOOK ONLY TO SUCH
+ * THIRD PARTY FOR ANY WARRANTY CLAIM RELATING THERETO. RECEIVER EXPRESSLY ACKNOWLEDGES
+ * THAT IT IS RECEIVER'S SOLE RESPONSIBILITY TO OBTAIN FROM ANY THIRD PARTY ALL PROPER LICENSES
+ * CONTAINED IN MEDIATEK SOFTWARE. MEDIATEK SHALL ALSO NOT BE RESPONSIBLE FOR ANY MEDIATEK
+ * SOFTWARE RELEASES MADE TO RECEIVER'S SPECIFICATION OR TO CONFORM TO A PARTICULAR
+ * STANDARD OR OPEN FORUM. RECEIVER'S SOLE AND EXCLUSIVE REMEDY AND MEDIATEK'S ENTIRE AND
+ * CUMULATIVE LIABILITY WITH RESPECT TO THE MEDIATEK SOFTWARE RELEASED HEREUNDER WILL BE,
+ * AT MEDIATEK'S OPTION, TO REVISE OR REPLACE THE MEDIATEK SOFTWARE AT ISSUE,
+ * OR REFUND ANY SOFTWARE LICENSE FEES OR SERVICE CHARGE PAID BY RECEIVER TO
+ * MEDIATEK FOR SUCH MEDIATEK SOFTWARE AT ISSUE.
+ *
+ * The following software/firmware and/or related documentation ("MediaTek Software")
+ * have been modified by MediaTek Inc. All revisions are subject to any receiver\'s
+ * applicable license agreements with MediaTek Inc.
+ */
+
+#pragma once
+
+/*
+  input:  data origin preloader data,
+          psz: in/output  data size, in origin preloader size, out: new preloader size.
+  return: -1: not a valid preloader. 0 OK.
+*/
+int process_preloader (char* data, /*IN OUT*/unsigned int* psz);
+/*
+ input:  data origin preloader data,
+ output: 1: preloader type is preloader_xxx.bin. 0: preloader type might be preloader.img
+*/
+int is_preloader_bin_format(char* data);
+
+#define HEADER_BLOCK_SIZE_COMBO               (4096)    // 4KB 0x1000
+#define HEADER_IDENTIFIER_COMBO               ("COMBO_BOOT")
+
+#define HEADER_BLOCK_SIZE_UFS                 (4096)    // 4KB 0x1000
+#define HEADER_IDENTIFIER_UFS                 ("UFS_BOOT")
+
+#define HEADER_BLOCK_SIZE_EMMC                (2048)    // 2KB 0x800
+#define HEADER_IDENTIFIER_EMMC                ("EMMC_BOOT")
+
+#define HEADER_BLOCK_SIZE_NAND                (2048)    // 2KB 0x800
+#define HEADER_IDENTIFIER_NAND                ("NAND_BOOT")
+

+ 236 - 0
app/mt_boot/bootargs.c

@@ -0,0 +1,236 @@
+/* Copyright Statement:
+*
+* This software/firmware and related documentation ("MediaTek Software") are
+* protected under relevant copyright laws. The information contained herein
+* is confidential and proprietary to MediaTek Inc. and/or its licensors.
+* Without the prior written permission of MediaTek inc. and/or its licensors,
+* any reproduction, modification, use or disclosure of MediaTek Software,
+* and information contained herein, in whole or in part, shall be strictly prohibited.
+*/
+/* MediaTek Inc. (C) 2018. All rights reserved.
+*
+* BY OPENING THIS FILE, RECEIVER HEREBY UNEQUIVOCALLY ACKNOWLEDGES AND AGREES
+* THAT THE SOFTWARE/FIRMWARE AND ITS DOCUMENTATIONS ("MEDIATEK SOFTWARE")
+* RECEIVED FROM MEDIATEK AND/OR ITS REPRESENTATIVES ARE PROVIDED TO RECEIVER ON
+* AN "AS-IS" BASIS ONLY. MEDIATEK EXPRESSLY DISCLAIMS ANY AND ALL WARRANTIES,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED WARRANTIES OF
+* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE OR NONINFRINGEMENT.
+* NEITHER DOES MEDIATEK PROVIDE ANY WARRANTY WHATSOEVER WITH RESPECT TO THE
+* SOFTWARE OF ANY THIRD PARTY WHICH MAY BE USED BY, INCORPORATED IN, OR
+* SUPPLIED WITH THE MEDIATEK SOFTWARE, AND RECEIVER AGREES TO LOOK ONLY TO SUCH
+* THIRD PARTY FOR ANY WARRANTY CLAIM RELATING THERETO. RECEIVER EXPRESSLY ACKNOWLEDGES
+* THAT IT IS RECEIVER'S SOLE RESPONSIBILITY TO OBTAIN FROM ANY THIRD PARTY ALL PROPER LICENSES
+* CONTAINED IN MEDIATEK SOFTWARE. MEDIATEK SHALL ALSO NOT BE RESPONSIBLE FOR ANY MEDIATEK
+* SOFTWARE RELEASES MADE TO RECEIVER'S SPECIFICATION OR TO CONFORM TO A PARTICULAR
+* STANDARD OR OPEN FORUM. RECEIVER'S SOLE AND EXCLUSIVE REMEDY AND MEDIATEK'S ENTIRE AND
+* CUMULATIVE LIABILITY WITH RESPECT TO THE MEDIATEK SOFTWARE RELEASED HEREUNDER WILL BE,
+* AT MEDIATEK'S OPTION, TO REVISE OR REPLACE THE MEDIATEK SOFTWARE AT ISSUE,
+* OR REFUND ANY SOFTWARE LICENSE FEES OR SERVICE CHARGE PAID BY RECEIVER TO
+* MEDIATEK FOR SUCH MEDIATEK SOFTWARE AT ISSUE.
+*/
+#include <stdio.h>
+#include <stdlib.h>
+#include <stddef.h>
+#include <assert.h>
+#include <bootargs.h>
+#include <errno.h>
+#include <string.h>
+#include <pal_log.h>
+#include <kernel/thread.h>
+#include <video.h>
+#include <libfdt.h>
+
+#define CMDLINE_OVERFLOW_STR	"[ERROR] CMDLINE overflow"
+
+static char g_cmdline[CMDLINE_LEN];
+static uint8_t bootargs_inited;
+static char *cmdline_tail = g_cmdline;
+static char *cmdline_end = g_cmdline + CMDLINE_LEN;
+
+/* define sensitive parameters to be cleared */
+static const char *cmdline_clear_list[] = {
+	"androidboot.serialno=",
+	NULL
+};
+
+static inline void validate_cmdline_boundary(const char *tail, const char *end)
+{
+	if (tail >= end) {
+		pal_log_err(CMDLINE_OVERFLOW_STR"\n");
+		video_printf(CMDLINE_OVERFLOW_STR" \n");
+		panic(CMDLINE_OVERFLOW_STR);
+	}
+}
+void bootargs_init(void *fdt)
+{
+#ifdef DEVICE_TREE_SUPPORT
+	int offset;
+	int len, n;
+	const void *fdt_bootargs = NULL;
+	const void *fdt_bootargs_ext = NULL;
+	char *temp_ptr = NULL;
+	uint32_t g_cmdline_strlen;
+
+	assert(fdt);
+	enter_critical_section();
+	if (bootargs_inited == 1) {
+		pal_log_err("bootargs has been initialized\n");
+		goto exit;
+	}
+	if (fdt == 0) {
+		pal_log_err("Device Tree is not inited!\n");
+		panic("fdt is NULL");
+	}
+	/* g_cmdline is filled with parameters before bootargs_init is called */
+	if (g_cmdline[0] != 0x0) {
+		g_cmdline_strlen = strlen(g_cmdline);
+		temp_ptr = (char *)malloc(g_cmdline_strlen + 1);
+		assert(temp_ptr);
+		n = snprintf(temp_ptr, (g_cmdline_strlen + 1), "%s", g_cmdline);
+		if (n < 0)
+			dprintf(INFO, "snprintf error in %s:%d\n", __FILE__, __LINE__);
+	}
+	/* Reset cmdline_tail */
+	cmdline_tail = g_cmdline;
+	offset = fdt_path_offset(fdt, "/chosen");
+	fdt_bootargs = fdt_getprop(fdt, offset,
+			"bootargs", &len);
+	assert(fdt_bootargs);
+	n = snprintf(cmdline_tail, CMDLINE_LEN, "%s", (char *)fdt_bootargs);
+	if (n < 0)
+		dprintf(INFO, "snprintf error in %s:%d\n", __FILE__, __LINE__);
+	else
+		cmdline_tail += n;
+	/*
+	 * According to DeviceTreeOverlayGuide.pdf, bootloader should
+	 * concatenate bootargs in main dtb with bootargs_ext in dtbo.
+	 */
+	fdt_bootargs_ext = fdt_getprop(fdt, offset,
+			"bootargs_ext", &len);
+	if (fdt_bootargs_ext != NULL) {
+		if (*(char *)fdt_bootargs_ext != 0) {
+			n = snprintf(cmdline_tail, cmdline_end - cmdline_tail, " %s", (char *)fdt_bootargs_ext);
+			if (n < 0)
+				dprintf(INFO, "snprintf error in %s:%d\n", __FILE__, __LINE__);
+			else
+				cmdline_tail += n;
+		}
+	}
+	if (temp_ptr != 0) {
+		n = snprintf(cmdline_tail, cmdline_end - cmdline_tail, "%s", temp_ptr);
+		if (n < 0)
+			dprintf(INFO, "snprintf error in %s:%d\n", __FILE__, __LINE__);
+		else
+			cmdline_tail += n;
+	}
+
+	bootargs_inited = 1;
+exit:
+	if (temp_ptr)
+		free(temp_ptr);
+	exit_critical_section();
+#else
+	UNUSED(fdt);
+#endif /* DEVICE_TREE_SUPPORT */
+}
+
+char *cmdline_get(void)
+{
+	return g_cmdline;
+}
+
+void cmdline_print(void)
+{
+	int i;
+	int temp_cmd_len = CMDLINE_LEN / 16;
+	int cmd_len = 0;
+	char *temp_cmdline = NULL;
+#ifdef USER_LOAD
+	bool ret;
+
+	ret = cmdline_clear_string();
+	if (!ret)
+		pal_log_err("cmdline clear not ok\n");
+#endif
+
+	cmd_len = strlen(g_cmdline);
+	pal_log_err("g_cmdline size: %d\n", cmd_len);
+
+	temp_cmdline = (char *)malloc(temp_cmd_len);
+	if (!temp_cmdline) {
+		pal_log_err("temp_cmdline malloc fail\n");
+		goto exit;
+	}
+
+	enter_critical_section();
+
+	for (i = 0; i < (cmd_len / (temp_cmd_len - 1)) + 1; i++) {
+		strncpy(temp_cmdline, &g_cmdline[(temp_cmd_len - 1) * i], (temp_cmd_len - 1));
+		temp_cmdline[temp_cmd_len - 1] = '\0';
+		if (i == 0)
+			pal_log_err("cmdline: %s\n", temp_cmdline);
+		else
+			pal_log_err("       : %s\n", temp_cmdline);
+	}
+
+	exit_critical_section();
+
+exit:
+	if (temp_cmdline)
+		free(temp_cmdline);
+}
+
+bool cmdline_append(const char *append_string)
+{
+	unsigned int append_string_len;
+
+	enter_critical_section();
+	append_string_len = strlen(append_string);
+	validate_cmdline_boundary((cmdline_tail + append_string_len + 1), cmdline_end);
+	*cmdline_tail++ = ' ';
+	strncat(cmdline_tail, append_string, cmdline_end - cmdline_tail);
+	cmdline_tail += append_string_len;
+	exit_critical_section();
+	return true;
+}
+
+bool cmdline_overwrite(const char *overwrite_string)
+{
+	int cmd_len;
+	cmd_len = strlen(overwrite_string);
+	if (cmd_len > CMDLINE_LEN - 1) {
+		pal_log_err(CMDLINE_OVERFLOW_STR"\n");
+		panic(CMDLINE_OVERFLOW_STR);
+		return false;
+	}
+	enter_critical_section();
+	strncpy(g_cmdline, overwrite_string, CMDLINE_LEN - 1);
+	exit_critical_section();
+	return true;
+}
+
+bool cmdline_clear_string(void)
+{
+	unsigned int i = 0;
+	char *ptr = NULL;
+
+	/* search parameters from cmdline */
+	for (i = 0; cmdline_clear_list[i] != NULL ; i++) {
+		size_t str_len = 0;
+
+		ptr = strstr(g_cmdline, cmdline_clear_list[i]);
+		if (ptr == NULL || ptr > cmdline_end) {
+			pal_log_err("[cmdline clear] extract %s fails\n", cmdline_clear_list[i]);
+			return false;
+		}
+
+		/* search 1st "space" character after key match ptr */
+		while (*(char *)(ptr+str_len) != ' ' && (ptr + str_len) < cmdline_end) str_len++;
+
+		pal_log_err("[cmdline clear] clear str size=%d\n", str_len);
+		memset(ptr, 0x78, str_len); //clear as xxxx
+		memcpy(ptr, cmdline_clear_list[i], strlen(cmdline_clear_list[i]));
+	}
+
+	return true;
+}

+ 42 - 0
app/mt_boot/bootargs.h

@@ -0,0 +1,42 @@
+/* Copyright Statement:
+*
+* This software/firmware and related documentation ("MediaTek Software") are
+* protected under relevant copyright laws. The information contained herein
+* is confidential and proprietary to MediaTek Inc. and/or its licensors.
+* Without the prior written permission of MediaTek inc. and/or its licensors,
+* any reproduction, modification, use or disclosure of MediaTek Software,
+* and information contained herein, in whole or in part, shall be strictly prohibited.
+*/
+/* MediaTek Inc. (C) 2018. All rights reserved.
+*
+* BY OPENING THIS FILE, RECEIVER HEREBY UNEQUIVOCALLY ACKNOWLEDGES AND AGREES
+* THAT THE SOFTWARE/FIRMWARE AND ITS DOCUMENTATIONS ("MEDIATEK SOFTWARE")
+* RECEIVED FROM MEDIATEK AND/OR ITS REPRESENTATIVES ARE PROVIDED TO RECEIVER ON
+* AN "AS-IS" BASIS ONLY. MEDIATEK EXPRESSLY DISCLAIMS ANY AND ALL WARRANTIES,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED WARRANTIES OF
+* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE OR NONINFRINGEMENT.
+* NEITHER DOES MEDIATEK PROVIDE ANY WARRANTY WHATSOEVER WITH RESPECT TO THE
+* SOFTWARE OF ANY THIRD PARTY WHICH MAY BE USED BY, INCORPORATED IN, OR
+* SUPPLIED WITH THE MEDIATEK SOFTWARE, AND RECEIVER AGREES TO LOOK ONLY TO SUCH
+* THIRD PARTY FOR ANY WARRANTY CLAIM RELATING THERETO. RECEIVER EXPRESSLY ACKNOWLEDGES
+* THAT IT IS RECEIVER'S SOLE RESPONSIBILITY TO OBTAIN FROM ANY THIRD PARTY ALL PROPER LICENSES
+* CONTAINED IN MEDIATEK SOFTWARE. MEDIATEK SHALL ALSO NOT BE RESPONSIBLE FOR ANY MEDIATEK
+* SOFTWARE RELEASES MADE TO RECEIVER'S SPECIFICATION OR TO CONFORM TO A PARTICULAR
+* STANDARD OR OPEN FORUM. RECEIVER'S SOLE AND EXCLUSIVE REMEDY AND MEDIATEK'S ENTIRE AND
+* CUMULATIVE LIABILITY WITH RESPECT TO THE MEDIATEK SOFTWARE RELEASED HEREUNDER WILL BE,
+* AT MEDIATEK'S OPTION, TO REVISE OR REPLACE THE MEDIATEK SOFTWARE AT ISSUE,
+* OR REFUND ANY SOFTWARE LICENSE FEES OR SERVICE CHARGE PAID BY RECEIVER TO
+* MEDIATEK FOR SUCH MEDIATEK SOFTWARE AT ISSUE.
+*/
+#if !defined (__BOOTARGS_H)
+#define __BOOTARGS_H
+#define CMDLINE_LEN   2048
+
+extern void bootargs_init(void *fdt);
+extern char *cmdline_get(void);
+extern void cmdline_print(void);
+extern bool cmdline_append(const char *append_string);
+extern bool cmdline_overwrite(const char *overwrite_string);
+extern bool cmdline_clear_string(void);
+#endif /* __BOOTARGS_H */
+

+ 146 - 0
app/mt_boot/decompressor.c

@@ -0,0 +1,146 @@
+/* Copyright Statement:
+*
+* This software/firmware and related documentation ("MediaTek Software") are
+* protected under relevant copyright laws. The information contained herein
+* is confidential and proprietary to MediaTek Inc. and/or its licensors.
+* Without the prior written permission of MediaTek inc. and/or its licensors,
+* any reproduction, modification, use or disclosure of MediaTek Software,
+* and information contained herein, in whole or in part, shall be strictly prohibited.
+*/
+/* MediaTek Inc. (C) 2017. All rights reserved.
+*
+* BY OPENING THIS FILE, RECEIVER HEREBY UNEQUIVOCALLY ACKNOWLEDGES AND AGREES
+* THAT THE SOFTWARE/FIRMWARE AND ITS DOCUMENTATIONS ("MEDIATEK SOFTWARE")
+* RECEIVED FROM MEDIATEK AND/OR ITS REPRESENTATIVES ARE PROVIDED TO RECEIVER ON
+* AN "AS-IS" BASIS ONLY. MEDIATEK EXPRESSLY DISCLAIMS ANY AND ALL WARRANTIES,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED WARRANTIES OF
+* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE OR NONINFRINGEMENT.
+* NEITHER DOES MEDIATEK PROVIDE ANY WARRANTY WHATSOEVER WITH RESPECT TO THE
+* SOFTWARE OF ANY THIRD PARTY WHICH MAY BE USED BY, INCORPORATED IN, OR
+* SUPPLIED WITH THE MEDIATEK SOFTWARE, AND RECEIVER AGREES TO LOOK ONLY TO SUCH
+* THIRD PARTY FOR ANY WARRANTY CLAIM RELATING THERETO. RECEIVER EXPRESSLY ACKNOWLEDGES
+* THAT IT IS RECEIVER'S SOLE RESPONSIBILITY TO OBTAIN FROM ANY THIRD PARTY ALL PROPER LICENSES
+* CONTAINED IN MEDIATEK SOFTWARE. MEDIATEK SHALL ALSO NOT BE RESPONSIBLE FOR ANY MEDIATEK
+* SOFTWARE RELEASES MADE TO RECEIVER'S SPECIFICATION OR TO CONFORM TO A PARTICULAR
+* STANDARD OR OPEN FORUM. RECEIVER'S SOLE AND EXCLUSIVE REMEDY AND MEDIATEK'S ENTIRE AND
+* CUMULATIVE LIABILITY WITH RESPECT TO THE MEDIATEK SOFTWARE RELEASED HEREUNDER WILL BE,
+* AT MEDIATEK'S OPTION, TO REVISE OR REPLACE THE MEDIATEK SOFTWARE AT ISSUE,
+* OR REFUND ANY SOFTWARE LICENSE FEES OR SERVICE CHARGE PAID BY RECEIVER TO
+* MEDIATEK FOR SUCH MEDIATEK SOFTWARE AT ISSUE.
+*/
+
+#include <lib/zlib.h>
+#include <string.h>
+#include <debug.h>
+#include <malloc.h>
+#include <platform/mt_gpt.h>	// for get_timer()
+#include <iothread.h>
+#include <profiling.h>
+
+#define RESERVED		0xe0
+#define COMMENT			0x10
+#define ORIG_NAME		8
+#define EXTRA_FIELD		4
+#define HEAD_CRC		2
+#define ZALLOC_ALIGNMENT	16
+
+static void *zlib_alloc(void *x, unsigned items, unsigned size)
+{
+	void *p;
+
+	size *= items;
+	size = (size + ZALLOC_ALIGNMENT - 1) & ~(ZALLOC_ALIGNMENT - 1);
+
+	p = malloc (size);
+	if (p == NULL)
+		dprintf(CRITICAL, "malloc(0x%x) fails in %s\n", size, __func__);
+ 	return (p);
+}
+
+static void zlib_free(void *x, void *addr)
+{
+	free (addr);
+}
+
+
+int zunzip(unsigned char *src, unsigned long *lenp, void *dst, int dstlen, int offset)
+{
+	z_stream s;
+	int r;
+
+	memset(&s, 0, sizeof(z_stream));
+
+	r = inflateInit2(&s, -MAX_WBITS);
+	if (r != Z_OK) {
+		dprintf (CRITICAL, "inflateInit2() error, returned %d\n", r);
+		return -1;
+	}
+	s.zalloc = zlib_alloc;
+	s.zfree = zlib_free;
+	s.next_in = src + offset;
+	s.next_out = dst;
+	s.avail_in = *lenp - offset;
+	s.avail_out = dstlen;
+	r = inflate(&s, Z_FINISH);
+	if ((r != Z_STREAM_END)) {
+		dprintf(CRITICAL, "inflate() error! return %d\n", r);
+		inflateEnd(&s);
+		return -1;
+	}
+	*lenp = s.next_out - (unsigned char *) dst;
+	inflateEnd(&s);
+
+	return 0;
+}
+
+int gunzip(unsigned char *src, unsigned long *lenp, void *dst, int dstlen)
+{
+	unsigned long i, flags;
+	int ret;
+
+	i = 10;
+	flags = src[3];
+
+	/* Skip the header of gzip */
+	if (src[2] != Z_DEFLATED || (flags & RESERVED) != 0) {
+		dprintf (CRITICAL, "gzip header is not correct. Error!\n");
+		return -1;
+	}
+	if ((flags & EXTRA_FIELD) != 0)
+		i = 12 + src[10] + (src[11] << 8);
+	if ((flags & ORIG_NAME) != 0)
+		while (src[i++] != 0)
+			;
+	if ((flags & COMMENT) != 0)
+		while (src[i++] != 0)
+			;
+	if ((flags & HEAD_CRC) != 0)
+		i += 2;
+
+	if (i >= *lenp) {
+		dprintf(CRITICAL, "gunzip header is bigger than expectation! Error!\n");
+		return -1;
+	}
+
+	ret = zunzip(src, lenp, dst, dstlen, i);
+
+	return ret;
+}
+
+
+bool decompress_kernel(unsigned char *in, void *out, int inlen, int outlen)
+{
+	unsigned long lenp = inlen;
+	int ret;
+
+	wake_up_iothread();
+
+	PROFILING_START("decompress_kernel");
+	ret = gunzip(in, &lenp, out, outlen);
+	PROFILING_END();
+
+	wait_for_iothread();
+
+	return ret;
+}
+

+ 1756 - 0
app/mt_boot/dl_commands.c

@@ -0,0 +1,1756 @@
+/* Copyright Statement:
+*
+* This software/firmware and related documentation ("MediaTek Software") are
+* protected under relevant copyright laws. The information contained herein
+* is confidential and proprietary to MediaTek Inc. and/or its licensors.
+* Without the prior written permission of MediaTek inc. and/or its licensors,
+* any reproduction, modification, use or disclosure of MediaTek Software,
+* and information contained herein, in whole or in part, shall be strictly prohibited.
+*/
+/* MediaTek Inc. (C) 2015. All rights reserved.
+*
+* BY OPENING THIS FILE, RECEIVER HEREBY UNEQUIVOCALLY ACKNOWLEDGES AND AGREES
+* THAT THE SOFTWARE/FIRMWARE AND ITS DOCUMENTATIONS ("MEDIATEK SOFTWARE")
+* RECEIVED FROM MEDIATEK AND/OR ITS REPRESENTATIVES ARE PROVIDED TO RECEIVER ON
+* AN "AS-IS" BASIS ONLY. MEDIATEK EXPRESSLY DISCLAIMS ANY AND ALL WARRANTIES,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED WARRANTIES OF
+* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE OR NONINFRINGEMENT.
+* NEITHER DOES MEDIATEK PROVIDE ANY WARRANTY WHATSOEVER WITH RESPECT TO THE
+* SOFTWARE OF ANY THIRD PARTY WHICH MAY BE USED BY, INCORPORATED IN, OR
+* SUPPLIED WITH THE MEDIATEK SOFTWARE, AND RECEIVER AGREES TO LOOK ONLY TO SUCH
+* THIRD PARTY FOR ANY WARRANTY CLAIM RELATING THERETO. RECEIVER EXPRESSLY ACKNOWLEDGES
+* THAT IT IS RECEIVER'S SOLE RESPONSIBILITY TO OBTAIN FROM ANY THIRD PARTY ALL PROPER LICENSES
+* CONTAINED IN MEDIATEK SOFTWARE. MEDIATEK SHALL ALSO NOT BE RESPONSIBLE FOR ANY MEDIATEK
+* SOFTWARE RELEASES MADE TO RECEIVER'S SPECIFICATION OR TO CONFORM TO A PARTICULAR
+* STANDARD OR OPEN FORUM. RECEIVER'S SOLE AND EXCLUSIVE REMEDY AND MEDIATEK'S ENTIRE AND
+* CUMULATIVE LIABILITY WITH RESPECT TO THE MEDIATEK SOFTWARE RELEASED HEREUNDER WILL BE,
+* AT MEDIATEK'S OPTION, TO REVISE OR REPLACE THE MEDIATEK SOFTWARE AT ISSUE,
+* OR REFUND ANY SOFTWARE LICENSE FEES OR SERVICE CHARGE PAID BY RECEIVER TO
+* MEDIATEK FOR SUCH MEDIATEK SOFTWARE AT ISSUE.
+*/
+
+#include <stdlib.h>
+#include <app.h>
+#include <debug.h>
+#include <arch/arm.h>
+#include <dev/udc.h>
+#include <string.h>
+#include <kernel/thread.h>
+#include <kernel/event.h>
+#include <arch/ops.h>
+#include <target.h>
+#include <platform.h>
+#include <platform/mt_reg_base.h>
+#include <platform/boot_mode.h>
+#include <platform/mtk_wdt.h>
+#include <platform/mt_rtc.h>
+#include <bootimg.h>
+#ifdef MTK_GPT_SCHEME_SUPPORT
+#include <platform/partition.h>
+#else
+#include <mt_partition.h>
+#endif
+#if !defined(MTK_EMMC_SUPPORT) && !defined(MTK_UFS_SUPPORT)
+#include <platform/mtk_nand.h>
+#endif
+#include <img_info.h>
+#include <part_interface.h>
+#include <block_generic_interface.h>
+
+/*For gpt update*/
+#ifdef MTK_GPT_SCHEME_SUPPORT
+#if defined(PLATFORM_FASTBOOT_EMPTY_STORAGE) || defined(MTK_GPT_UPDATE_SUPPORT)
+extern part_t *partition;
+extern int gpt_partition_table_update(const char *arg, void *data, unsigned sz);
+extern int read_gpt(part_t *part);
+#endif
+#endif
+
+/*For image write*/
+#include "sparse_format.h"
+#include "dl_commands.h"
+#ifdef MTK_MMC_COMBO_DRV
+#include <mmc_core.h>
+#else
+#include <platform/mmc_core.h>
+#endif
+#include <platform/mt_gpt.h>
+#include <platform/errno.h>
+#ifdef FASTBOOT_WHOLE_FLASH_SUPPORT
+extern part_t *partition;
+extern int read_gpt(part_t *part);
+#endif
+
+#include "fastboot.h"
+#include "mt_pmic.h"
+#include "blockheader.h"
+
+#ifdef MTK_ULTRA_FLASH
+#include "transfer.h"
+#endif
+
+#ifdef MBLOCK_LIB_SUPPORT
+#include <mblock.h>
+#endif
+
+
+#define MODULE_NAME "FASTBOOT_DOWNLOAD"
+#define MAX_RSP_SIZE 64
+
+extern void *download_base;
+#if defined(MTK_MLC_NAND_SUPPORT) || defined(MTK_TLC_NAND_SUPPORT)
+extern unsigned long long download_max;
+#else
+extern unsigned download_max;
+#endif
+extern unsigned download_size;
+extern unsigned fastboot_state;
+
+/*LXO: !Download related command*/
+
+#define ROUND_TO_PAGE(x,y) (((x) + (y)) & (~(y)))
+#define INVALID_PTN -1
+//For test: Display info on boot screen
+#define DISPLAY_INFO_ON_LCM
+#if (defined(MTK_UFS_SUPPORT) || defined(MTK_EMMC_SUPPORT))  //use another macro.
+#define EMMC_TYPE
+#else
+#define NAND_TYPE
+#endif
+#if defined(MTK_SPI_NOR_SUPPORT)
+#define NOR_TYPE
+#endif
+extern void video_printf (const char *fmt, ...);
+extern int video_get_rows(void);
+extern void video_set_cursor(int row, int col);
+extern void video_clean_screen(void);
+#if defined(MTK_MLC_NAND_SUPPORT) || defined(MTK_TLC_NAND_SUPPORT)
+extern int nand_write_img(u64 addr, void *data, u32 img_sz,u64 partition_size,int partition_type);
+extern int nand_write_img_ex(u64 addr, void *data, u32 length,u64 total_size, u32 *next_offset, u64 partition_start,u64 partition_size, int img_type);
+#else
+extern int nand_write_img(u32 addr, void *data, u32 img_sz,u32 partition_size,int partition_type);
+extern int nand_write_img_ex(u32 addr, void *data, u32 length,u32 total_size, u32 *next_offset, u32 partition_start,u32 partition_size, int img_type);
+#endif
+extern u32 gpt4_tick2time_ms (u32 tick);
+
+unsigned start_time_ms;
+#define TIME_STAMP gpt4_tick2time_ms(gpt4_get_current_tick())
+#define TIME_START {start_time_ms = gpt4_tick2time_ms(gpt4_get_current_tick());}
+#define TIME_ELAPSE (gpt4_tick2time_ms(gpt4_get_current_tick()) - start_time_ms)
+
+extern int usb_write(void *buf, unsigned len);
+extern int usb_read(void *buf, unsigned len);
+
+
+extern int sec_dl_permission_chk(const char *part_name, unsigned int *permitted);
+extern int sec_format_permission_chk(const char *part_name, unsigned int *permitted);
+
+bool flash_storage(const char* arg, void* data, unsigned sz);
+
+/* todo: give lk strtoul and nuke this */
+static u64 hex2uint64(const char *x)
+{
+	u64 n = 0;
+
+	while (*x) {
+		switch (*x) {
+			case '0':
+			case '1':
+			case '2':
+			case '3':
+			case '4':
+			case '5':
+			case '6':
+			case '7':
+			case '8':
+			case '9':
+				n = (n << 4) | (*x - '0');
+				break;
+			case 'a':
+			case 'b':
+			case 'c':
+			case 'd':
+			case 'e':
+			case 'f':
+				n = (n << 4) | (*x - 'a' + 10);
+				break;
+			case 'A':
+			case 'B':
+			case 'C':
+			case 'D':
+			case 'E':
+			case 'F':
+				n = (n << 4) | (*x - 'A' + 10);
+				break;
+			default:
+				return n;
+		}
+		x++;
+	}
+
+	return n;
+}
+
+static unsigned hex2unsigned(const char *x)
+{
+	return (unsigned)hex2uint64(x);
+}
+
+extern BOOT_ARGUMENT *g_boot_arg;
+void* special_heap_alloc(int length)
+{
+	void* buf = (void*)(u32)mblock_reserve_ext(&g_boot_arg->mblock_info,
+		length, 0x10000, 0xC0000000, 0, "fastboot_heap");
+
+	return buf;
+}
+
+static void init_display_xy()
+{
+#if defined(DISPLAY_INFO_ON_LCM)
+	video_clean_screen();
+	video_set_cursor(video_get_rows()/2, 0);
+	//video_set_cursor(1, 0);
+#endif
+}
+
+static void display_info(const char* msg)
+{
+#if defined(DISPLAY_INFO_ON_LCM)
+	if (msg == 0) {
+		return;
+	}
+	video_printf("%s\n", msg);
+#endif
+}
+
+void display_progress(const char* msg_prefix, unsigned size, unsigned totle_size)
+{
+#if defined(DISPLAY_INFO_ON_LCM)
+	unsigned vel = 0;
+	u64 prog = 0;
+	unsigned time = TIME_ELAPSE;
+
+
+	if (msg_prefix == 0) {
+		msg_prefix = "Unknown";
+	}
+
+	if (time != 0) {
+		vel = (unsigned)(size / time); //approximate  1024/1000
+		vel /= 1000;
+		time /= 1000;
+	}
+	if (totle_size != 0) {
+		prog = (u64)size*100/totle_size;
+	}
+	video_printf("%s > %3d%% Time:%4d s Vel:%3d MB/s             ", msg_prefix, (unsigned)prog, time, vel);
+#endif
+}
+
+static void display_speed_info(const char* msg_prefix, unsigned size)
+{
+#if defined(DISPLAY_INFO_ON_LCM)
+	unsigned vel = 0;
+	unsigned time = TIME_ELAPSE;
+
+	if (msg_prefix == 0) {
+		msg_prefix = "Unknown";
+	}
+
+	if (time != 0) {
+		vel = (unsigned)(size / time); //approximate  1024/1000
+		vel /= 1000;
+		time /= 1000;
+	}
+	video_printf("\n%s  Time:%d s Vel:%d MB/s \n", msg_prefix, time, vel);
+#endif
+}
+
+static void fastboot_fail_wrapper(const char* msg)
+{
+	display_info(msg);
+	fastboot_fail(msg);
+}
+
+static void fastboot_ok_wrapper(const char* msg, unsigned data_size)
+{
+	display_speed_info(msg, data_size);
+	fastboot_okay("");
+}
+void cmd_install_sig(const char *arg, void *data, unsigned sz)
+{
+	fastboot_fail_wrapper("Signature command not supported");
+}
+
+static char error_msg[512];
+void set_response_msg(const char* s)
+{
+    strncpy(error_msg, s, 511);
+}
+
+bool power_check()
+{
+	//3500 mV. shut down threshold 3.45V
+	if (get_bat_sense_volt(5) < 3500) {
+		return false;
+	} else {
+		return true;
+	}
+}
+
+#ifdef MTK_ULTRA_FLASH
+bool g_ultra_flash_enable = true;
+char partition_name_history[MAX_PARTITION_NAME_LEN]={0};
+int partition_name_history_len = 0;
+void switch_max_download_len(bool ultra_en);
+bool is_special_partition(const char* partition);
+bool cmd_download_ultra(const char *arg, void *data, unsigned sz);
+bool cmd_download_standard(const char *arg, void *data, unsigned sz);
+#endif
+
+void cmd_download(const char *arg, void *data, unsigned sz)
+{
+	bool result = false;
+#ifdef MTK_ULTRA_FLASH
+	if(g_ultra_flash_enable && (partition_name_history_len!=0) && (!is_special_partition(partition_name_history)))
+	{
+		result = cmd_download_ultra(arg, data, sz);
+	}
+	else
+	{
+		result = cmd_download_standard(arg, data, sz);
+	}
+	if(!result)
+	{
+		//restore the default max download size.
+		switch_max_download_len(false);
+	}
+#else
+	cmd_download_standard(arg, data, sz);
+#endif
+	return;
+}
+
+bool cmd_download_standard(const char *arg, void *data, unsigned sz)
+{
+	char response[MAX_RSP_SIZE];
+	unsigned len = hex2unsigned(arg);
+	int r;
+	if (!power_check()) {
+		fastboot_fail("low power, need battery charging.");
+		return false;
+	}
+	init_display_xy();
+	download_size = 0;
+	if (len > download_max) {
+		fastboot_fail_wrapper("data is too large");
+		return false;
+	}
+	if(snprintf(response, MAX_RSP_SIZE, "DATA%08x", len) < 0)
+        {
+            fastboot_fail("ghost snprintf error.");
+            return false;
+        }
+	if (usb_write(response, strlen(response)) < 0) {
+		return false;
+	}
+	display_info("USB Transferring... ");
+	TIME_START;
+	r = usb_read(download_base, len);
+	if ((r < 0) || ((unsigned) r != len)) {
+		fastboot_fail_wrapper("Read USB error");
+		fastboot_state = STATE_ERROR;
+		return false;
+	}
+	download_size = len;
+
+	fastboot_ok_wrapper("USB Transmission OK", len);
+	return true;
+}
+
+#ifdef NAND_TYPE
+int get_nand_image_type(const char* arg)
+{
+	int img_type = 0;
+	if (!strncmp(arg, "system", strlen("system")) ||
+		!strcmp(arg, "userdata") ||
+		!strcmp(arg, "fat") ) {
+#if defined(MTK_NAND_UBIFS_SUPPORT) || defined(MTK_NAND_MTK_FTL_SUPPORT)
+			img_type = UBIFS_IMG;
+#else
+			img_type = YFFS2_IMG;
+#endif
+	} else {
+		img_type = RAW_DATA_IMG;
+	}
+	return img_type;
+}
+#endif
+
+extern part_dev_t *mt_part_get_device(void);
+bool cmd_flash_mmc_img(const char* arg, void* data, unsigned sz)
+{
+	unsigned long long ptn = 0;
+	unsigned long long size = 0;
+	part_dev_t *dev;
+	int index = INVALID_PTN;
+
+#if (defined(MTK_UFS_SUPPORT) || defined(MTK_NEW_COMBO_EMMC_SUPPORT))
+	unsigned int part_id;
+#endif
+
+
+#ifdef MTK_SPI_NOR_SUPPORT
+	if (!strcmp(arg, "NOR")) {
+		ptn = 0;
+		part_id = 0; /* If need, example : NOR_PART_BOOT1 */
+		goto write_nor_part;
+	} else
+#endif
+
+#ifdef FASTBOOT_WHOLE_FLASH_SUPPORT
+		if (!strcmp(arg, "boot0")) {
+			ptn = 0;
+			part_id = EMMC_PART_BOOT1;
+			mmc_emmc_boot_prepare();
+			goto write_part;
+		} else if (!strcmp(arg,"boot1")) {
+			ptn = 0;
+			part_id  = EMMC_PART_BOOT2;
+			goto write_part;
+		} else if (!strcmp(arg, "partition")) {
+			ptn = 0;
+			part_id = EMMC_PART_USER;
+			goto write_part;
+		}
+#else
+		if (!strcmp(arg, "partition")) {
+			dprintf(ALWAYS, "Attempt to write partition image.\n");
+            set_response_msg("Do not support this operation.");
+            return false;
+		}
+#endif
+		else {
+			index = partition_get_index(arg);
+			if (index == INVALID_PTN) {
+                set_response_msg("This partition doesn't exist");
+                return false;
+			}
+			ptn = partition_get_offset(index);
+			if (ptn == (unsigned long long)(-1)) {
+                set_response_msg("partition table doesn't exist");
+                return false;
+			}
+#if (defined(MTK_UFS_SUPPORT) || defined(MTK_NEW_COMBO_EMMC_SUPPORT))
+			part_id = partition_get_region(index);
+#endif
+
+			if (!strcmp(arg, "boot") || !strcmp(arg, "boot_a") ||
+			!strcmp(arg, "boot_b") || !strcmp(arg, "recovery")) {
+				if (memcmp((void *)data, BOOTIMG_MAGIC, BOOTIMG_MAGIC_SZ-1)) {
+                    set_response_msg("image is not a boot image");
+                    return false;
+				}
+			}
+			if (!strncmp(arg, "preloader", strlen("preloader"))) {
+				dev = mt_part_get_device();
+
+#if (defined(MTK_EMMC_SUPPORT) || defined(MTK_UFS_SUPPORT))
+				if (dev->blkdev->type == BOOTDEV_SDMMC) {
+					int boot_wp = mmc_get_card(0)->raw_ext_csd[EXT_CSD_BOOT_WP];
+					if (boot_wp & EXT_CSD_BOOT_WP_EN_PERM_WP) {
+                        set_response_msg("flash preloader is not permitted.");
+                        return false;
+                    }
+                }
+#endif
+
+#ifdef PLATFORM_FASTBOOT_EMPTY_STORAGE
+                if (process_preloader(data, &sz)) {
+                    set_response_msg("not a valid preloader.");
+                    return false;
+                }
+                ptn = 0;
+#else
+				if (is_preloader_bin_format(data)) {
+					//preloader_xxx.bin
+					if (dev->blkdev->type == BOOTDEV_SDMMC)
+						ptn = HEADER_BLOCK_SIZE_EMMC;
+					else if (dev->blkdev->type == BOOTDEV_UFS)
+						ptn = HEADER_BLOCK_SIZE_UFS;
+					else
+						ptn = HEADER_BLOCK_SIZE_NAND;
+				}
+				else  //migh be preloader.img. offset = 0
+					ptn = 0;
+
+#endif
+			}
+
+			size = partition_get_size(index);
+			if (ROUND_TO_PAGE(sz,511) > size) {
+                set_response_msg("size too large");
+                return false;
+            }
+        }
+
+#ifdef FASTBOOT_WHOLE_FLASH_SUPPORT
+write_part:
+#endif  // FASTBOOT_WHOLE_FLASH_SUPPORT
+
+#ifdef EMMC_TYPE
+#if (defined(MTK_UFS_SUPPORT) || defined(MTK_NEW_COMBO_EMMC_SUPPORT))
+		dprintf (ALWAYS, "partid %d, addr 0x%llx, size 0x%x\n", part_id, ptn, sz);
+		if (emmc_write(part_id, ptn , (unsigned int *)data, sz) != sz)
+#else
+		if (emmc_write(ptn , (unsigned int *)data, sz) != sz)
+#endif
+#endif
+
+#ifdef NAND_TYPE
+#if defined(MTK_MLC_NAND_SUPPORT) || defined(MTK_TLC_NAND_SUPPORT)
+			if (nand_write_img((u64)ptn, (char*)data, sz,(u64)size,get_nand_image_type(arg)))
+#else
+			if (nand_write_img((u32)ptn, (char*)data, sz,(u32)size,get_nand_image_type(arg)))
+#endif
+#endif
+			{
+                       set_response_msg("flash write failure");
+                       return false;
+			}
+#ifdef FASTBOOT_WHOLE_FLASH_SUPPORT
+			if (!strcmp(arg, "partition")) {
+				read_gpt(partition);
+			}
+#endif
+               //fastboot_okay("");
+               return true;
+
+#ifdef NOR_TYPE
+#ifdef MTK_SPI_NOR_SUPPORT
+write_nor_part:
+
+			dprintf (ALWAYS, "partid %d, addr 0x%llx, size 0x%x\n", part_id, ptn, sz);
+			if (nor_write_part(part_id, ptn , (unsigned int *)data, (u64)sz) != sz) {
+                                  set_response_msg("SPI NOR flash write failure");
+                                  return false;
+			}
+                              //fastboot_okay("");
+                              return false;
+#endif
+#endif
+}
+
+bool cmd_flash_mmc_sparse_img(const char* arg, void* data, unsigned sz)
+{
+	unsigned int chunk;
+	unsigned int chunk_data_sz;
+	static uint32_t *fill_buf = NULL;
+	uint32_t fill_val;
+	uint32_t chunk_blk_cnt = 0;
+	uint32_t i;
+	unsigned long long size_wrote = 0;
+	sparse_header_t *sparse_header;
+	chunk_header_t *chunk_header;
+	uint32_t total_blocks = 0;
+	unsigned long long ptn = 0;
+	unsigned long long size = 0;
+	int index = INVALID_PTN;
+#if (defined(MTK_UFS_SUPPORT) || defined(MTK_NEW_COMBO_EMMC_SUPPORT))
+	unsigned int part_id;
+#endif
+
+	index = partition_get_index(arg);
+	if (INVALID_PTN == index) {
+        set_response_msg("This partition doesn't exist");
+        return false;
+	}
+
+	ptn = partition_get_offset(index);
+	if (ptn == (unsigned long long)(-1)) {
+        set_response_msg("partition offset is wrong");
+        return false;
+	}
+	dprintf(ALWAYS, "partition(%s) index is %d, ptn is 0x%llx\n", arg, index, ptn);
+#if (defined(MTK_UFS_SUPPORT) || defined(MTK_NEW_COMBO_EMMC_SUPPORT))
+	part_id = partition_get_region(index);
+#endif
+
+	size = partition_get_size(index);
+
+	/* Read and skip over sparse image header */
+	sparse_header = (sparse_header_t *) data;
+	dprintf(ALWAYS, "Image size span 0x%llx, partition size 0x%llx\n", (unsigned long long)sparse_header->total_blks*sparse_header->blk_sz, size);
+	if ((unsigned long long)sparse_header->total_blks*sparse_header->blk_sz > size) {
+        set_response_msg("sparse image size span overflow.");
+        return false;
+	}
+
+	if(sparse_header->file_hdr_sz > sz)
+	{
+        set_response_msg("sparse image header invalid.");
+        return false;
+	}
+	data += sizeof(sparse_header_t);
+	if (sparse_header->file_hdr_sz > sizeof(sparse_header_t)) {
+		/* Skip the remaining bytes in a header that is longer than
+		* we expected.
+		*/
+		data += (sparse_header->file_hdr_sz - sizeof(sparse_header_t));
+	}
+
+	dprintf (ALWAYS, "=== Sparse Image Header ===\n");
+	dprintf (ALWAYS, "magic: 0x%x\n", sparse_header->magic);
+	dprintf (ALWAYS, "major_version: 0x%x\n", sparse_header->major_version);
+	dprintf (ALWAYS, "minor_version: 0x%x\n", sparse_header->minor_version);
+	dprintf (ALWAYS, "file_hdr_sz: %d\n", sparse_header->file_hdr_sz);
+	dprintf (ALWAYS, "chunk_hdr_sz: %d\n", sparse_header->chunk_hdr_sz);
+	dprintf (ALWAYS, "blk_sz: %d\n", sparse_header->blk_sz);
+	dprintf (ALWAYS, "total_blks: %d\n", sparse_header->total_blks);
+	dprintf (ALWAYS, "total_chunks: %d\n", sparse_header->total_chunks);
+
+	display_info("\nWriting Flash ... ");
+	/* Start processing chunks */
+	for (chunk=0; chunk<sparse_header->total_chunks; chunk++) {
+		/* Read and skip over chunk header */
+		chunk_header = (chunk_header_t *)data;
+		data += sizeof(chunk_header_t);
+
+		//dprintf (ALWAYS, "=== Chunk Header ===\n");
+		//dprintf (ALWAYS, "chunk_type: 0x%x\n", chunk_header->chunk_type);
+		//dprintf (ALWAYS, "chunk_data_sz: 0x%x\n", chunk_header->chunk_sz);
+		//dprintf (ALWAYS, "total_size: 0x%x\n", chunk_header->total_sz);
+
+		if (sparse_header->chunk_hdr_sz > sizeof(chunk_header_t)) {
+			/* Skip the remaining bytes in a header that is longer than
+			* we expected.
+			*/
+			data += (sparse_header->chunk_hdr_sz - sizeof(chunk_header_t));
+		}
+
+		if(size/sparse_header->blk_sz < chunk_header->chunk_sz)
+		{
+            set_response_msg("sparse chunk size is too big.");
+            return false;
+        }
+		chunk_data_sz = sparse_header->blk_sz * chunk_header->chunk_sz;
+
+		//check chunk bounadary
+		if(sparse_header->blk_sz * ((unsigned long long)chunk_header->chunk_sz + total_blocks) > size)
+		{
+            set_response_msg("sparse chunk size overflow.");
+            return false;
+		}
+		if((sparse_header->total_blks - total_blocks) < chunk_header->chunk_sz)
+		{
+            set_response_msg("sparse chunk blocks bigger than total blocks.");
+            return false;
+		}
+		switch (chunk_header->chunk_type) {
+			case CHUNK_TYPE_RAW:
+			{
+				if (chunk_header->total_sz != (sparse_header->chunk_hdr_sz +
+					chunk_data_sz)) {
+                set_response_msg("Bogus chunk size for chunk type Raw");
+                return false;
+				}
+
+				dprintf (ALWAYS, "Raw: start block addr: 0x%x\n", total_blocks);
+
+#ifdef EMMC_TYPE
+#if (defined(MTK_UFS_SUPPORT) || defined(MTK_NEW_COMBO_EMMC_SUPPORT))
+				//dprintf (ALWAYS, "partid %d, addr 0x%llx, partsz 0x%x\n", part_id, ptn + ((unsigned long long)total_blocks*sparse_header->blk_sz) , chunk_data_sz);
+				if (emmc_write(part_id, ptn + ((unsigned long long)total_blocks*sparse_header->blk_sz) , data, chunk_data_sz) != chunk_data_sz)
+#else
+				if (emmc_write(ptn + ((unsigned long long)total_blocks*sparse_header->blk_sz) , data, chunk_data_sz) != chunk_data_sz)
+#endif
+#endif
+
+#ifdef NAND_TYPE
+#if defined(MTK_MLC_NAND_SUPPORT) || defined(MTK_TLC_NAND_SUPPORT)
+					if (nand_write_img((u64)(ptn + ((unsigned long long)total_blocks*sparse_header->blk_sz)), (char*)data, chunk_data_sz,(u64)size,get_nand_image_type(arg)))
+#else
+					if (nand_write_img((u32)(ptn + ((unsigned long long)total_blocks*sparse_header->blk_sz)), (char*)data, chunk_data_sz,(u32)size,get_nand_image_type(arg)))
+#endif
+#endif
+					{
+                    set_response_msg("flash write failure");
+                    return false;
+					}
+
+					total_blocks += chunk_header->chunk_sz;
+					data += chunk_data_sz;
+					break;
+			}
+			case CHUNK_TYPE_DONT_CARE:
+			{
+				dprintf (ALWAYS, "!!Blank: start: 0x%x  offset: 0x%x\n", total_blocks, chunk_header->chunk_sz);
+				total_blocks += chunk_header->chunk_sz;
+				break;
+			}
+			case CHUNK_TYPE_FILL:
+			{
+				dprintf (ALWAYS, "%s %d: CHUNK_TYPE_FILL=0x%x size=%d chunk_data_sz=%d\n", __FUNCTION__, __LINE__, *(uint32_t *)data, ROUNDUP(sparse_header->blk_sz, CACHE_LINE), chunk_data_sz);
+				if (chunk_header->total_sz != (sparse_header->chunk_hdr_sz + sizeof(uint32_t))) {
+                set_response_msg("Bogus chunk size for chunk type FILL");
+                return false;
+				}
+
+#define FILL_BUF_BLOCK_CNT ((4*1024*1024)/sparse_header->blk_sz)
+#define FILL_BUF_LEN (FILL_BUF_BLOCK_CNT * sparse_header->blk_sz)
+				//fill_buf = (uint32_t *)memalign(CACHE_LINE, FILL_BUF_LEN);
+				if(fill_buf == NULL)
+				{
+					fill_buf = special_heap_alloc(FILL_BUF_LEN);
+				}
+				if (!fill_buf) {
+                set_response_msg("Malloc failed for: CHUNK_TYPE_FILL");
+                return false;
+				}
+
+				fill_val = *(uint32_t *)data;
+				data = (char *) data + sizeof(uint32_t);
+				chunk_blk_cnt = chunk_data_sz / sparse_header->blk_sz;
+
+				unsigned int int_cnt = FILL_BUF_LEN / sizeof(fill_val);
+				for (i = 0; i < int_cnt; i++) {
+					fill_buf[i] = fill_val;
+				}
+
+
+				unsigned int left = chunk_blk_cnt;
+				while (left > 0) {
+
+					unsigned int todo = (left > FILL_BUF_BLOCK_CNT) ? FILL_BUF_BLOCK_CNT : left;
+#if (defined(MTK_UFS_SUPPORT) || defined(MTK_NEW_COMBO_EMMC_SUPPORT))
+					size_wrote = emmc_write(part_id, ptn + ((uint64_t)total_blocks*sparse_header->blk_sz),
+						fill_buf, (u64)todo * sparse_header->blk_sz);
+#else
+					size_wrote = emmc_write(ptn + ((uint64_t)total_blocks*sparse_header->blk_sz),
+						fill_buf, (u64)todo * sparse_header->blk_sz);
+#endif
+
+					if (size_wrote != (unsigned long long)todo * sparse_header->blk_sz) {
+                    set_response_msg("CHUNK_TYPE_FILL flash write failure");
+                    //free(fill_buf);
+                    return false;
+					}
+
+					total_blocks += todo;
+					left -= todo;
+				}
+
+				//free(fill_buf);
+
+				break;
+			}
+			case CHUNK_TYPE_CRC:
+			{
+				if (chunk_header->total_sz != sparse_header->chunk_hdr_sz) {
+                set_response_msg("Bogus chunk size for chunk type Dont Care");
+                return false;
+				}
+				total_blocks += chunk_header->chunk_sz;
+				data += chunk_data_sz;
+				break;
+			}
+			default:
+            set_response_msg("Unknown chunk type");
+            return false;
+		}
+		display_progress("\rWrite Data", total_blocks*sparse_header->blk_sz, sparse_header->total_blks*sparse_header->blk_sz);
+	}
+
+	dprintf(ALWAYS, "Wrote %d blocks, expected to write %d blocks\n",
+		total_blocks, sparse_header->total_blks);
+
+	if (total_blocks != sparse_header->total_blks) {
+        set_response_msg("sparse image write failure");
+		return false;
+	} else {
+		display_info("\n\nOK");
+		fastboot_okay("");
+	}
+
+    return true;
+}
+extern int mboot_recovery_load_raw_part_offset(char *part_name, unsigned long *addr, unsigned long offset, unsigned int size) __attribute__((weak));
+
+int _virtual_partition_support(const char *arg, void *data, unsigned int* p_sz, char **modified_arg)
+{
+#define TMP_DOWNLOAD_SIZE   52*1024*1024    //52MB, because kernel size(64M) - pagetable max size (8M) - ramdisk size(Estimate 4M)
+
+	unsigned t_bootimg_addr = ((u32)data);
+	void* new_data =(void *)((u32)data + SCRATCH_SIZE - TMP_DOWNLOAD_SIZE);
+	bool _is_zimage = false;
+	struct bootimg_hdr *p_boot_hdr;
+	unsigned int t_kernel_addr;
+	unsigned int t_ramdisk_addr;
+	unsigned int sz = *p_sz;
+	char* tmp = (void *)arg;
+	int ret;
+
+	if (!memcmp(arg, "zimage", strlen("zimage"))) {
+		_is_zimage = true;
+		dprintf(INFO,"Get zimage\n");
+	} else if (!memcmp(arg, "ramdisk", strlen("ramdisk"))) {
+		dprintf(INFO,"Get ramdisk\n");
+	} else {
+		return 0;
+	}
+	/* check size first */
+	if (sz > TMP_DOWNLOAD_SIZE)
+		return -ENOMEM;
+
+	/* copy ori data to temp addr */
+	memcpy(new_data, data, sz);
+	/* copy bootimg header content */
+	//clean space for img_hdr make the debug easier, 8k is enough for most case (page size < 8k)
+	memset(data, 0, 0x2000);
+#ifdef MTK_GPT_SCHEME_SUPPORT
+	ret = mboot_recovery_load_raw_part_offset("boot", (void *)t_bootimg_addr, 0, sizeof(struct bootimg_hdr));
+#else
+	ret = mboot_recovery_load_raw_part_offset(PART_BOOTIMG, (void *)t_bootimg_addr, 0, sizeof(struct bootimg_hdr));
+#endif
+	if (ret < 0) {
+		return ret;
+	}
+	p_boot_hdr = (void *)t_bootimg_addr;
+	dprintf(INFO,"ori kernel_sz: %x\n", p_boot_hdr->kernel_sz);
+	dprintf(INFO,"ori ramdisk_sz: %x\n", p_boot_hdr->ramdisk_sz);
+
+	t_kernel_addr = t_bootimg_addr + p_boot_hdr->page_sz;
+	if (_is_zimage == true) {
+		/* copy kernel content from new_data*/
+		memcpy((void *)t_kernel_addr, new_data, sz);
+		/* copy ramdisk content from flash */
+		t_ramdisk_addr = ROUNDUP(t_kernel_addr + sz, p_boot_hdr->page_sz);
+#ifdef MTK_GPT_SCHEME_SUPPORT
+		ret = mboot_recovery_load_raw_part_offset("boot", (void *)t_ramdisk_addr,
+			ROUNDUP(p_boot_hdr->kernel_sz + p_boot_hdr->page_sz, p_boot_hdr->page_sz), p_boot_hdr->ramdisk_sz);
+#else
+		ret = mboot_recovery_load_raw_part_offset(PART_BOOTIMG, (void *)t_ramdisk_addr,
+			ROUNDUP(p_boot_hdr->kernel_sz + p_boot_hdr->page_sz, p_boot_hdr->page_sz), p_boot_hdr->ramdisk_sz);
+#endif
+
+		if (ret < 0) {
+			return ret;
+		}
+		/* update header */
+		p_boot_hdr->kernel_sz = sz;
+		dprintf(INFO,"->kernel_sz %x\n", sz);
+	} else {
+		/* copy kernel content from flash*/
+#ifdef MTK_GPT_SCHEME_SUPPORT
+		ret = mboot_recovery_load_raw_part_offset("boot", (void *)t_kernel_addr, p_boot_hdr->page_sz, p_boot_hdr->kernel_sz);
+#else
+		ret = mboot_recovery_load_raw_part_offset(PART_BOOTIMG, (void *)t_kernel_addr, p_boot_hdr->page_sz, p_boot_hdr->kernel_sz);
+#endif
+		if (ret < 0) {
+			return ret;
+		}
+
+		t_ramdisk_addr = ROUNDUP(t_kernel_addr + p_boot_hdr->kernel_sz, p_boot_hdr->page_sz);
+		/* copy ramdisk content from new_data*/
+		memcpy((void *)t_ramdisk_addr, new_data, sz);
+		/* update header */
+		p_boot_hdr->ramdisk_sz = sz;
+
+		dprintf(INFO,"->ramdisk_sz %x\n", sz);
+	}
+
+	/* overwrite arg*/
+	*p_sz = p_boot_hdr->page_sz + ROUNDUP(p_boot_hdr->kernel_sz, p_boot_hdr->page_sz)+ ROUNDUP(p_boot_hdr->ramdisk_sz, p_boot_hdr->page_sz);
+
+	/*
+	* FIXME or LIMITATION:
+	* tmp is an argument passed all the way from the handle() function. The handle() function
+	* is a legacy of the official little kernel release. If the length of the destination
+	* buffer "tmp" is needed, the function prototype of handle() needs to have one more
+	* argument. In other words, all the functions registered in fastboot need to be altered.
+	*/
+
+	/* 4 for the string, "boot", 1 for terminater, '\0'*/
+	//if (strlen(tmp) >= 5) /*tmp was 'ramdisk' or 'zimage'. Add check to avoid "Out-of-bound access" coverity scan.*/
+	//	strncpy(tmp, "boot", 4 + 1);
+	if (strlen(tmp) >= 5 && modified_arg != 0)
+		*modified_arg = "boot";
+	return 0;
+
+}
+
+
+/******************************************************************************
+* The mkimage tool will round up the image size to 16-byte alignment boundary
+* by padding zero to the tail of the image before a 512-byte mkimage header is
+* "pre-pended" to it. The dsize field in the mkimage header is the real size
+* of the image content before padding is applied, and it does not include the
+* size of the header.
+*
+* The preloader image does not have a mkimage header by default. To make the
+* flow consistent, a mkimage header is "pre-pended" to the preloader before it
+* is concatenated to the "single boot loader". Please note that the header
+* along with the image content of an image (except for the preloader image)
+* needs to be flashed to the storage. In other words, do not flash the mkimage
+* header of the preloader to the storage. It is fine to flash the padding bytes
+* to the storage.
+******************************************************************************/
+bool cmd_flash_mmc_standard(const char *arg, void *data, unsigned sz);
+void cmd_flash_mmc(const char *arg, void *data, unsigned sz)
+{
+#ifdef MTK_ULTRA_FLASH
+	bool result = false;
+	if(g_ultra_flash_enable && (partition_name_history_len!=0) && (!is_special_partition(partition_name_history)))
+	{
+		fastboot_info(partition_name_history);
+		fastboot_okay("");
+		result = true;
+	}
+	else
+	{
+        result = flash_storage(arg, data, sz);
+	}
+	if(!result)
+	{
+		//restore the default max download size.
+		switch_max_download_len(false);
+	}
+#else
+    flash_storage(arg, data, sz);
+#endif
+	return;
+}
+
+#define UNI_BOOTLOADER_MAGIC 0xEF77FD33
+#define MAX_BOOTLOADER_IMAGE 16
+
+
+struct partition_cell
+{
+   char name[32];
+   unsigned int size;
+};
+
+struct uni_bootloader_hdr
+{
+   unsigned int magic;  //0xEF77FD33
+   unsigned int version;  //1
+   unsigned int header_size; // total header's size
+   unsigned int image_cnt; //images count
+   struct partition_cell part_list[MAX_BOOTLOADER_IMAGE];
+};
+
+bool flash_storage(const char* arg, void* data, unsigned sz)
+{
+	bool result = false;
+    if (strcmp(arg, "singlebootloader") != 0 && strcmp(arg, "bootloader") != 0)
+    {
+        result = cmd_flash_mmc_standard(arg, data, sz);
+        if (result)
+        {
+            fastboot_okay("");
+        }
+        else
+        {
+            fastboot_fail(error_msg);
+        }
+
+        return result;
+    }
+
+    dprintf(ALWAYS, "@download singlebootloader.\n");
+    dprintf(ALWAYS, "@size 0x%x.\n", sz);
+
+    struct uni_bootloader_hdr* hdr = data;
+    if(hdr->magic != UNI_BOOTLOADER_MAGIC
+        || hdr->image_cnt > MAX_BOOTLOADER_IMAGE
+        || hdr->header_size != sizeof(struct uni_bootloader_hdr))
+    {
+        fastboot_fail("NOT UNI_BOOTLOADER_MAGIC OR COUNT OVERFLOW.");
+        return false;
+    }
+
+    void* img_data = data + hdr->header_size;
+    unsigned int idx = 0;
+    for (;idx < hdr->image_cnt; ++idx)
+    {
+        dprintf(ALWAYS, "@split download %s.\n", hdr->part_list[idx].name);
+		bool result = cmd_flash_mmc_standard(hdr->part_list[idx].name, img_data,
+            hdr->part_list[idx].size);
+
+	if (!result)
+	{
+		fastboot_fail(error_msg);
+		return false;
+	}
+
+		img_data += hdr->part_list[idx].size;
+    }
+
+    fastboot_okay("");
+	return result;
+}
+bool cmd_flash_mmc_standard(const char *arg, void *data, unsigned sz)
+{
+    bool result = false;
+#ifdef MTK_SECURITY_SW_SUPPORT
+	unsigned int permitted = 0;
+	char msg[64];
+#endif
+#ifdef MTK_GPT_SCHEME_SUPPORT
+#if defined(PLATFORM_FASTBOOT_EMPTY_STORAGE) || defined(MTK_GPT_UPDATE_SUPPORT)
+	int err;
+#endif
+#endif
+	union mkimg_hdr *part_hdr;
+	bool single_boot_loader = false;
+	bool flash_tee2 = false;  // If ATF was found, flash both tee1 and tee2.
+
+	if (sz  == 0) {
+        //fastboot_okay("");
+		return true;
+	}
+
+	if (!strcmp(arg, "singlebootloader"))
+		single_boot_loader = true;
+
+	u32 remaining_len = sz;
+	u32 counter = 5;
+	while (remaining_len && (counter > 0)) {
+		part_hdr = (union mkimg_hdr *)data;
+		if (single_boot_loader) {
+			if (flash_tee2) {
+				arg = "tee2";
+				flash_tee2 = false;
+			} else {
+				arg = part_hdr->info.name;
+				if ((!strncmp(arg, "lk", 3)) || (!strncmp(arg, "LK", 3))) {
+					arg = "lk";
+					sz = sizeof(union mkimg_hdr);
+				}
+				else if ((!strncmp(arg, "logo", 5)) || (!strncmp(arg, "LOGO", 5))) {
+					arg = "logo";
+					sz = sizeof(union mkimg_hdr);
+				}
+				else if ((!strncmp(arg, "atf", 4)) || (!strncmp(arg, "ATF", 4))) {
+					arg = "tee1";
+					sz = sizeof(union mkimg_hdr);
+					flash_tee2 = true;
+				}
+				else if ((!strncmp(arg, "preloader", 10)) || (!strncmp(arg, "PRELOADER", 10))) {
+					arg = "preloader";
+					sz = 0;
+					data += sizeof(union mkimg_hdr);
+					if (remaining_len < sizeof(union mkimg_hdr)) {
+						set_response_msg("not enough remaining length");
+						return false;
+					}
+					remaining_len -= sizeof(union mkimg_hdr);
+				}
+				else {
+					set_response_msg("unknown data");
+					return false;
+				}
+				sz += ROUNDUP(part_hdr->info.dsz, 16);
+				if (remaining_len < sz) {
+					set_response_msg("not enough remaining length");
+					return false;
+				}
+			}
+		}
+
+		// security check here.
+		// ret = decrypt_scm((uint32 **) &data, &sz);
+#ifdef MTK_SECURITY_SW_SUPPORT
+		if (sec_dl_permission_chk(arg, &permitted)) {
+			if(snprintf(msg, sizeof(msg), "failed to get download permission for partition '%s'\n", arg) < 0)
+			{
+				fastboot_fail("ghost snprintf error.");
+				return false;
+			}
+			set_response_msg(msg);
+			return false;
+		}
+
+		if (0 == permitted) {
+			if(snprintf(msg, sizeof(msg), "download for partition '%s' is not allowed\n", arg) < 0)
+			{
+				fastboot_fail("ghost snprintf error.");
+				return false;
+			}
+            set_response_msg(msg);
+			return false;
+		}
+#endif
+#ifdef MTK_GPT_SCHEME_SUPPORT
+#if defined(PLATFORM_FASTBOOT_EMPTY_STORAGE) || defined(MTK_GPT_UPDATE_SUPPORT)
+		if (!strcmp(arg, "gpt")) { //if arg == "gpt" , update pmbr, pgpt, and sgpt. Then re-init partition table for fastboot.
+			err = gpt_partition_table_update(arg, data, sz);
+			if (err) {
+				set_response_msg("failed to update gpt partition");
+				return false;
+			}
+			read_gpt(partition); //re-init partition table afster update pmbor, pgpt and sgpt
+			register_partition_var();
+            //fastboot_okay("");
+			return true;
+		}
+#endif
+#endif
+		TIME_START;
+                char *modified_arg = 0;
+		if (_virtual_partition_support(arg, data, &sz, &modified_arg) < 0) {
+                        set_response_msg("virtual partition write fail");
+			return false;
+		}
+		else { /* is boot virtual partition, ex:ramdisk */
+			if (remaining_len < sz)
+				remaining_len = sz;
+		}
+
+		if(modified_arg != 0)
+                        arg = modified_arg;
+
+		sparse_header_t *sparse_header = (sparse_header_t *) data;
+		if (sparse_header->magic != SPARSE_HEADER_MAGIC)
+			result = cmd_flash_mmc_img(arg, data, sz);
+		else
+#ifdef NAND_TYPE
+	#ifdef MNTL_SUPPORT
+		{
+		if (is_mntl_partition(arg))
+			{
+                dprintf(CRITICAL, "%s: mntl partition %s\n",
+                    __FUNCTION__, arg);
+				result = mntl_flash_img(arg, data, sz);
+                if (!result)
+				{
+                    set_response_msg("mntl flash image err.");
+					return false;
+                }
+            }
+            else
+            {
+                result = cmd_flash_nand_sparse_img(arg, data, sz);
+            }
+        }
+#else
+	{
+            result = cmd_flash_nand_sparse_img(arg, data, sz);
+	}
+#endif
+#endif
+
+#ifdef EMMC_TYPE
+		{
+        	result = cmd_flash_mmc_sparse_img(arg, data, sz);
+		}
+#endif
+		if(!result)
+		{
+		    return result;
+		}
+		if (flash_tee2) {
+			counter--;
+			continue;  // Preserve "data" and "sz" for reuse.
+		}
+		remaining_len -= sz;
+		data += sz;
+		counter--;
+	}
+
+    return result;
+}
+
+void cmd_erase_mmc(const char *arg, void *data, unsigned sz)
+{
+#if (defined(MTK_UFS_SUPPORT) || defined(MTK_NEW_COMBO_EMMC_SUPPORT))
+	unsigned int part_id;
+#endif
+	unsigned long long ptn = 0;
+	unsigned long long size = 0;
+	int index = INVALID_PTN;
+	int erase_ret = MMC_ERR_NONE;
+#ifdef MTK_SECURITY_SW_SUPPORT
+	unsigned int permitted = 0;
+	char msg[64];
+#endif
+
+	dprintf (ALWAYS, "cmd_erase_mmc\n");
+
+#ifdef MTK_SPI_NOR_SUPPORT
+	if (!strcmp(arg, "NOR")) {
+		ptn = 0;
+		size = nor_get_device_capacity();
+		part_id = 0;/* NOR_PART_BOOT1; */
+		goto erase_nor_part;
+	} else
+#endif
+
+#ifdef FASTBOOT_WHOLE_FLASH_SUPPORT
+		if (!strcmp(arg, "boot0")) {
+			ptn = 0;
+			size = mmc_get_region_size(EMMC_PART_BOOT1);
+			part_id = EMMC_PART_BOOT1;
+		} else if (!strcmp(arg, "boot1")) {
+			ptn = 0;
+			size = mmc_get_region_size(EMMC_PART_BOOT2);
+			part_id = EMMC_PART_BOOT2;
+		} else if (!strcmp(arg, "partition")) {
+			ptn = 0;
+			size = mmc_get_region_size(EMMC_PART_USER);
+			part_id = EMMC_PART_USER;
+		} else
+#endif
+		{
+			index = partition_get_index(arg);
+			if (index == -1) {
+				fastboot_fail_wrapper("Partition table doesn't exist");
+				return;
+			}
+
+#ifdef MTK_SECURITY_SW_SUPPORT
+			if (sec_format_permission_chk(arg, &permitted)) {
+				if(snprintf(msg, sizeof(msg), "failed to get format permission for partition '%s'\n", arg) < 0)
+				{
+					fastboot_fail("ghost snprintf error.");
+					return;
+				}
+				fastboot_fail(msg);
+				return;
+			}
+
+			if (0 == permitted) {
+				if(snprintf(msg, sizeof(msg), "format for partition '%s' is not allowed\n", arg) < 0)
+				{
+					fastboot_fail("ghost snprintf error.");
+					return;
+				}
+				fastboot_fail(msg);
+				return;
+			}
+#endif
+
+#if (defined(MTK_UFS_SUPPORT) || defined(MTK_NEW_COMBO_EMMC_SUPPORT))
+			part_id = partition_get_region(index);
+#endif
+			ptn = partition_get_offset(index);
+
+			size = partition_get_size(index);
+		}
+		TIME_START;
+#ifdef EMMC_TYPE
+#if (defined(MTK_UFS_SUPPORT) || defined(MTK_NEW_COMBO_EMMC_SUPPORT))
+		erase_ret = emmc_erase(part_id, ptn, size);
+#else
+		erase_ret = emmc_erase(ptn, size);
+#endif
+#endif
+
+#ifdef NAND_TYPE
+	#ifdef MNTL_SUPPORT
+	if (is_mntl_partition(arg)) {
+		dprintf(ALWAYS, "%s: mntl partition %s\n",
+			 __FUNCTION__, arg);
+		erase_ret = mntl_erase(arg, data, sz);
+	} else
+		erase_ret = nand_erase(ptn,size);
+	#else
+	erase_ret = nand_erase(ptn,size);
+	#endif
+#endif
+
+		if (erase_ret  == MMC_ERR_NONE) {
+			fastboot_ok_wrapper("OK", size);
+		} else {
+			fastboot_fail_wrapper("Erase error.");
+		}
+
+		return;
+
+#ifdef NOR_TYPE
+erase_nor_part:
+
+		dprintf (ALWAYS, "partid %d, addr 0x%llx, size 0x%llx\n", part_id, ptn, size);
+		erase_ret = nor_erase_part(part_id, ptn, size);
+
+		if (erase_ret  == 0/* NOR_ERR_NONE */) { /* NOR_ERR_NONE suppose to be zero */
+			fastboot_ok_wrapper("OK", size);
+		} else {
+			fastboot_fail_wrapper("Erase SPI NOR flash error.");
+		}
+
+		return;
+#endif
+}
+
+
+/****************NEW CACHE WRITE*************************/
+#if defined(NAND_TYPE)
+
+typedef struct data_cache {
+	unsigned char* base;
+	unsigned int len;
+	unsigned int offset;
+	unsigned int blocks_per_cache;
+	bool is_first_write;
+	bool valid_data;
+} data_cache_t;
+
+data_cache_t* cache;
+static void memfill(unsigned int* addr, unsigned int value, unsigned int count)
+{
+	unsigned int i = 0;
+	for (; i<count; ++i) {
+		addr[i] = value;
+	}
+	return;
+}
+
+typedef struct nand_arg {
+	unsigned long long ptn;
+	unsigned int img_type;
+	unsigned long long size; //partition size
+} nand_arg_t;
+
+extern int nand_get_alignment();
+unsigned int get_cache_size()
+{
+	return (unsigned int)nand_get_alignment();
+}
+extern int nand_img_read(unsigned long long source, unsigned char * dst, int size);
+
+static bool cached_write_data(unsigned int* start_blocks, char* data, unsigned long long data_sz,unsigned int chunk_type, unsigned int sparse_blk_sz, void* arg)
+{
+	unsigned long long byte_to_process = data_sz;
+	unsigned int byte_processed = 0;
+	bool skip_zero_copy = false; //only affect CHUNK_TYPE_DONT_CARE
+	unsigned int total_blocks = *start_blocks;
+
+	nand_arg_t* nand = (nand_arg_t*)arg;
+
+	while (byte_to_process != 0) {
+		unsigned int slot_len = (byte_to_process > cache->len - cache->offset) ? cache->len - cache->offset :byte_to_process;
+		if (chunk_type == CHUNK_TYPE_RAW ||chunk_type == CHUNK_TYPE_FILL) {
+			if (cache->is_first_write && (!cache->valid_data) && cache->offset!=0) {
+#if defined(MTK_MLC_NAND_SUPPORT)
+				nand_img_read((u64)(nand->ptn + ((unsigned long long)total_blocks*sparse_blk_sz)), (char*)cache->base, cache->len);
+#else
+				nand_img_read((u32)(nand->ptn + ((unsigned long long)total_blocks*sparse_blk_sz)), (char*)cache->base, cache->len);
+#endif
+				dprintf(ALWAYS, "Read ptn = 0x%llx, Address 0x%x = 0x%x\n", nand->ptn, total_blocks,*(int*)cache->base);
+				cache->is_first_write = false;
+			}
+		}
+
+		if (chunk_type == CHUNK_TYPE_RAW) {
+			memcpy(cache->base+cache->offset, data+byte_processed, slot_len);
+			cache->valid_data = true;
+		} else if (chunk_type == CHUNK_TYPE_DONT_CARE ) {
+			if (!cache->valid_data) {
+				skip_zero_copy = true;
+			}
+			if (!skip_zero_copy)
+				memset(cache->base+cache->offset, 0xFF, slot_len);
+		} else if (chunk_type == CHUNK_TYPE_FILL) {
+			memfill((unsigned int*)(cache->base+cache->offset), *(unsigned int*)data, slot_len/sizeof(unsigned int));
+			cache->valid_data = true;
+		}
+
+		cache->offset += slot_len;
+
+		if (cache->offset == cache->len) { //cache full
+			dprintf(ALWAYS, "@@@@write At block(x4K) 0x%x\n", total_blocks);
+			if (!skip_zero_copy) {
+
+
+#if defined(MTK_MLC_NAND_SUPPORT)
+				dprintf(ALWAYS, "Address 0x%x = 0x%x\n", total_blocks,*(int*)cache->base);
+				if (nand_write_img((u64)(nand->ptn + ((unsigned long long)total_blocks*sparse_blk_sz)), (char*)cache->base, cache->len,nand->size,nand->img_type))
+#else
+				if (nand_write_img((u32)(nand->ptn + ((unsigned long long)total_blocks*sparse_blk_sz)), (char*)cache->base, cache->len,nand->size,nand->img_type))
+#endif
+
+				{
+					dprintf(ALWAYS, "@@@@write failed\n");
+					return false;
+				}
+			}
+			cache->offset = 0;   //start new package.
+			byte_to_process -= slot_len;
+			byte_processed += slot_len;
+			total_blocks += cache->blocks_per_cache;
+			cache->valid_data = false;
+		} else {
+			//can not full cache.
+			break;
+		}
+
+		if (chunk_type == CHUNK_TYPE_DONT_CARE) {
+			skip_zero_copy = true;
+		}
+	}
+	*start_blocks = total_blocks;
+	return true;
+}
+
+
+
+bool cmd_flash_nand_sparse_img(const char* arg, void* data, unsigned sz)
+{
+	unsigned int chunk;
+	unsigned long long chunk_data_sz;
+	sparse_header_t *sparse_header;
+	chunk_header_t *chunk_header;
+	uint32_t total_blocks = 0;
+	unsigned long long ptn = 0;
+	unsigned long long size = 0;
+	int index = INVALID_PTN;
+
+
+
+	nand_arg_t sto_arg;
+	sto_arg.img_type = get_nand_image_type(arg);
+
+	unsigned int crc_value;
+	unsigned int fill_value;
+	data_cache_t cache_inst;
+	cache_inst.len = get_cache_size();
+	cache_inst.base = (unsigned char*)memalign(128, cache_inst.len);
+	cache_inst.offset = 0;
+	cache_inst.is_first_write = true;
+	cache_inst.valid_data = false;
+	cache = &cache_inst;
+
+	index = partition_get_index(arg);
+	sto_arg.ptn = partition_get_offset(index);
+	if (sto_arg.ptn == (unsigned long long)(-1)) {
+		set_response_msg("partition table doesn't exist");
+		goto exit;
+	}
+
+
+	sto_arg.size = partition_get_size(index);
+
+	/* Read and skip over sparse image header */
+	sparse_header = (sparse_header_t *) data;
+	dprintf(ALWAYS, "Image size span 0x%llx, partition size 0x%llx\n", (unsigned long long)sparse_header->total_blks*sparse_header->blk_sz, sto_arg.size);
+	if ((unsigned long long)sparse_header->total_blks*sparse_header->blk_sz > sto_arg.size) {
+        set_response_msg("sparse image size span overflow.");
+		goto exit;
+	}
+
+	data += sparse_header->file_hdr_sz;
+	if (sparse_header->file_hdr_sz > sizeof(sparse_header_t)) {
+		/* Skip the remaining bytes in a header that is longer than
+		* we expected.
+		*/
+		data += (sparse_header->file_hdr_sz - sizeof(sparse_header_t));
+	}
+
+	cache->blocks_per_cache = (cache->len/sparse_header->blk_sz);
+	dprintf (ALWAYS, "=== Sparse Image Header ===\n");
+	dprintf (ALWAYS, "magic: 0x%x\n", sparse_header->magic);
+	dprintf (ALWAYS, "major_version: 0x%x\n", sparse_header->major_version);
+	dprintf (ALWAYS, "minor_version: 0x%x\n", sparse_header->minor_version);
+	dprintf (ALWAYS, "file_hdr_sz: %d\n", sparse_header->file_hdr_sz);
+	dprintf (ALWAYS, "chunk_hdr_sz: %d\n", sparse_header->chunk_hdr_sz);
+	dprintf (ALWAYS, "blk_sz: %d\n", sparse_header->blk_sz);
+	dprintf (ALWAYS, "total_blks: %d\n", sparse_header->total_blks);
+	dprintf (ALWAYS, "total_chunks: %d\n", sparse_header->total_chunks);
+
+	display_info("\nWriting Flash ... ");
+	/* Start processing chunks */
+	for (chunk=0; chunk<sparse_header->total_chunks; chunk++) {
+		/* Read and skip over chunk header */
+		chunk_header = (chunk_header_t *) data;
+		data += sizeof(chunk_header_t);
+
+		//dprintf (ALWAYS, "=== Chunk Header ===\n");
+		//dprintf (ALWAYS, "chunk_type: 0x%x\n", chunk_header->chunk_type);
+		//dprintf (ALWAYS, "chunk_data_sz: 0x%x\n", chunk_header->chunk_sz);
+		//dprintf (ALWAYS, "total_size: 0x%x\n", chunk_header->total_sz);
+
+		if (sparse_header->chunk_hdr_sz > sizeof(chunk_header_t)) {
+			/* Skip the remaining bytes in a header that is longer than
+			* we expected.
+			*/
+			data += (sparse_header->chunk_hdr_sz - sizeof(chunk_header_t));
+		}
+
+		chunk_data_sz = (unsigned long long)(sparse_header->blk_sz&0xFFFFFFFF);
+		chunk_data_sz = chunk_data_sz * chunk_header->chunk_sz;
+		switch (chunk_header->chunk_type) {
+			case CHUNK_TYPE_RAW:
+				if (chunk_header->total_sz != (sparse_header->chunk_hdr_sz +
+					chunk_data_sz)) {
+						//fastboot_fail("Bogus chunk size for chunk type Raw");
+						goto exit;
+				}
+
+
+				if (!cached_write_data(&total_blocks, data, chunk_data_sz, CHUNK_TYPE_RAW, sparse_header->blk_sz, (void*)&sto_arg)) {
+                set_response_msg("storage write failed.");
+					goto exit;
+				}
+				data += chunk_data_sz;
+
+				break;
+
+			case CHUNK_TYPE_DONT_CARE:
+				if (!cached_write_data(&total_blocks, 0, chunk_data_sz, CHUNK_TYPE_DONT_CARE, sparse_header->blk_sz, (void*)&sto_arg)) {
+                set_response_msg("storage write failed.");
+					goto exit;
+				}
+				break;
+			case CHUNK_TYPE_CRC:
+				crc_value = *(unsigned int*)data;
+				data += 4;
+				break;
+
+			case CHUNK_TYPE_FILL:
+				fill_value = *(unsigned int*)data;
+
+				if (!cached_write_data(&total_blocks, (char*)&fill_value, chunk_data_sz, CHUNK_TYPE_FILL, sparse_header->blk_sz, (void*)&sto_arg)) {
+                set_response_msg("storage write failed.");
+					goto exit;
+				}
+				data += 4;  //data length is 4.
+				break;
+			default:
+            set_response_msg("Unknown chunk type");
+				goto exit;
+		}
+		display_progress("\rWrite Data", total_blocks*sparse_header->blk_sz, sparse_header->total_blks*sparse_header->blk_sz);
+	}
+
+	/******************/
+	//last cache
+	if (cache->offset != 0) {
+
+#if defined(MTK_MLC_NAND_SUPPORT)
+		if (nand_write_img((u64)(sto_arg.ptn + ((unsigned long long)total_blocks*sparse_header->blk_sz)), (char*)cache->base, cache->offset,sto_arg.size,sto_arg.img_type))
+#else
+		if (nand_write_img((u32)(sto_arg.ptn + ((unsigned long long)total_blocks*sparse_header->blk_sz)), (char*)cache->base, cache->offset,sto_arg.size,sto_arg.img_type))
+#endif
+
+			total_blocks += cache->offset/sparse_header->blk_sz;
+	}
+	/******************/
+
+	dprintf(ALWAYS, "Wrote %d blocks, expected to write %d blocks\n",
+		total_blocks, sparse_header->total_blks);
+
+	if (total_blocks != sparse_header->total_blks) {
+        set_response_msg("sparse image write failure");
+	} else {
+		display_info("\n\nOK");
+        //fastboot_okay("");
+        if (cache->base) free(cache->base);
+		return true;
+	}
+exit:
+	if (cache->base) free(cache->base);
+    return false;
+}
+
+#endif
+/**********END********/
+
+
+
+
+#ifdef MTK_ULTRA_FLASH
+
+#define MAX_SPECIAL_P 17
+char* special_partition[MAX_SPECIAL_P] = {
+    "preloader", "boot", "boot0", "boot1", "tee", "tee1", "bootloader"
+    , "tee2", "lk", "logo", "atf", "recovery", "partition", "singlebootloader", "gpt", "pgpt","mbr"
+};
+bool is_special_partition(const char* partition)
+{
+	int idx = 0;
+	for(; idx<MAX_SPECIAL_P; ++idx)
+	{
+		if (strnicmp(special_partition[idx], partition, 32) == 0)
+		{
+			return true;
+		}
+	}
+
+	return false;
+}
+char* trim_space(const char *str)
+{
+	char* p = (char*)str;
+	if(p == NULL)return NULL;
+	while(*p && (*p==' ' || *p == '\t'))
+	{
+		++p;
+	}
+	return p;
+}
+extern void fastboot_update_var(const char *name, const char *value);
+extern const char * fastboot_get_var(const char *name);
+
+void cmd_oem_ultra_flash(const char *arg, void *data, unsigned sz)
+{
+	char response[MAX_RSP_SIZE];
+
+	if(!g_ultra_flash_enable)
+	{
+		if(snprintf(response, MAX_RSP_SIZE, "Ultra-flash Disabled. [%s]", fastboot_get_var("max-download-size")) < 0)
+		{
+			fastboot_fail("ghost sprintf error.");
+			return;
+		}
+		fastboot_info(response);
+		fastboot_okay("");
+		return;
+	}
+
+	char* part = trim_space(arg);
+	if(part == 0)
+	{
+		fastboot_fail("ultra flash arg is null.");
+		return;
+	}
+	if(strnlen(part, MAX_PARTITION_NAME_LEN+3) >= MAX_PARTITION_NAME_LEN)
+	{
+		fastboot_fail("name too long.");
+		return;
+	}
+
+	memset(partition_name_history, 0, MAX_PARTITION_NAME_LEN);
+	partition_name_history_len = strnlen(part, MAX_PARTITION_NAME_LEN-1);
+	strncpy(partition_name_history, part, MAX_PARTITION_NAME_LEN-1);
+	partition_name_history[MAX_PARTITION_NAME_LEN-1] = 0;
+
+	switch_max_download_len((partition_name_history_len != 0) && (!is_special_partition(partition_name_history)));
+
+	if(snprintf(response, MAX_RSP_SIZE, "%s. [%s]", partition_name_history, fastboot_get_var("max-download-size")) < 0)
+	{
+		fastboot_fail("name too long.");
+		return;
+	}
+
+	fastboot_info(response);
+	fastboot_okay("");
+}
+
+void switch_max_download_len(bool ultra_en)
+{
+	static const char* dl_max_str_history = NULL;
+	static const char* dl_max_str = "0x200000000";
+	if(dl_max_str_history == NULL)
+	{
+		dl_max_str_history = fastboot_get_var("max-download-size");
+	}
+
+	fastboot_update_var("max-download-size", ultra_en? dl_max_str:dl_max_str_history);
+}
+
+void cmd_oem_ultra_flash_en(const char *arg, void *data, unsigned sz)
+{
+	char response[MAX_RSP_SIZE];
+	if (!strncmp(arg, " 1", strlen(" 1")))
+	{
+		//turn ultra flash on
+		fastboot_info("Enable ultra-flash.");
+		g_ultra_flash_enable = true;
+	}
+	else if (!strncmp(arg, " 0", strlen(" 0")))
+	{
+		//turn ultra flash off
+		fastboot_info("Disable ultra-flash.");
+		g_ultra_flash_enable = false;
+
+	} else {
+		if(snprintf(response, MAX_RSP_SIZE, "\tCurrent ultra-flash setting:%s",
+			g_ultra_flash_enable ? "Enabled" : "Disabled") < 0)
+		{
+			fastboot_fail("ghost snprintf error.");
+			return;
+		}
+		fastboot_info(response);
+	}
+	fastboot_okay("");
+}
+
+extern char * strncpy(char *dest, char const *src, size_t count);
+bool cmd_download_ultra(const char *arg, void *data, unsigned sz)
+{
+	int index = INVALID_PTN;
+	status_t status = STATUS_OK;
+
+	char response[MAX_RSP_SIZE];
+	uint64 len = hex2uint64(arg);
+
+	if (!power_check())
+	{
+		fastboot_fail("low power, need battery charging.");
+		return false;
+	}
+	init_display_xy();
+
+	if(snprintf(response, MAX_RSP_SIZE, "DATA%08llx", len) < 0)
+	{
+		fastboot_fail("ghost snprintf error.");
+		return false;
+	}
+	if (usb_write(response, strlen(response)) < 0) {
+		return false;
+	}
+	display_info("USB Bulk Transferring... ");
+
+	LOGI("[%s]", partition_name_history);
+	struct partition_info_struct part_info;
+	memset(&part_info, 0, sizeof(struct partition_info_struct));
+	index = partition_get_index(partition_name_history);
+	if (index == INVALID_PTN)
+	{
+		fastboot_fail("This partition doesn't exist");
+		return false;
+	}
+
+	strncpy((char*)part_info.name, partition_name_history, MAX_PARTITION_NAME_LEN-1);
+	part_info.base_addr = partition_get_offset(index);
+	if (part_info.base_addr == (unsigned long long)(-1))
+	{
+		fastboot_fail("partition table doesn't exist");
+		return false;
+	}
+
+	part_info.part_id = partition_get_region(index);
+	part_info.max_size  = partition_get_size(index);
+
+	LOGI("download part_name[%s] base_addr[0x%llx] part_max_sz[0x%llx] down_len [0x%llx]\n",
+		part_info.name, part_info.base_addr, part_info.max_size, len);
+	TIME_START;
+	status = download_data(len, &part_info);
+
+	if(FAIL(status))
+	{
+		if(snprintf(response, MAX_RSP_SIZE, "Transmission FAIL: [%d]", status) < 0)
+		{
+			fastboot_fail("ghost snprintf error.");
+			return false;
+		}
+		fastboot_fail_wrapper(response);
+		fastboot_state = STATE_ERROR;
+		return false;
+	}
+
+	fastboot_ok_wrapper("Transmission OK", len);
+	return true;
+}
+
+void* get_available_ram_base()
+{
+	return download_base;
+}
+
+#endif
+
+/*LXO: END!Download related command*/

+ 24 - 0
app/mt_boot/dl_commands.h

@@ -0,0 +1,24 @@
+#ifndef __DOWNLOAD_COMMANDS_H
+#define __DOWNLOAD_COMMANDS_H
+#include <platform/mt_typedefs.h>
+
+
+void cmd_install_sig(const char *arg, void *data, unsigned sz);
+bool cmd_flash_mmc_img(const char *arg, void *data, unsigned sz);
+bool cmd_flash_mmc_sparse_img(const char *arg, void *data, unsigned sz);
+void cmd_flash_mmc(const char *arg, void *data, unsigned sz);
+void cmd_erase_mmc(const char *arg, void *data, unsigned sz);
+
+
+
+
+#ifdef MTK_ULTRA_FLASH
+void cmd_oem_ultra_flash(const char *arg, void *data, unsigned sz);
+void cmd_oem_ultra_flash_en(const char *arg, void *data, unsigned sz);
+//internal use.
+void display_progress(const char* msg_prefix, unsigned size, unsigned totle_size);
+void* get_available_ram_base();
+void* special_heap_alloc(int length);
+#endif
+
+#endif

+ 1015 - 0
app/mt_boot/fastboot.c

@@ -0,0 +1,1015 @@
+/* Copyright Statement:
+*
+* This software/firmware and related documentation ("MediaTek Software") are
+* protected under relevant copyright laws. The information contained herein
+* is confidential and proprietary to MediaTek Inc. and/or its licensors.
+* Without the prior written permission of MediaTek inc. and/or its licensors,
+* any reproduction, modification, use or disclosure of MediaTek Software,
+* and information contained herein, in whole or in part, shall be strictly prohibited.
+*/
+/* MediaTek Inc. (C) 2015. All rights reserved.
+*
+* BY OPENING THIS FILE, RECEIVER HEREBY UNEQUIVOCALLY ACKNOWLEDGES AND AGREES
+* THAT THE SOFTWARE/FIRMWARE AND ITS DOCUMENTATIONS ("MEDIATEK SOFTWARE")
+* RECEIVED FROM MEDIATEK AND/OR ITS REPRESENTATIVES ARE PROVIDED TO RECEIVER ON
+* AN "AS-IS" BASIS ONLY. MEDIATEK EXPRESSLY DISCLAIMS ANY AND ALL WARRANTIES,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED WARRANTIES OF
+* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE OR NONINFRINGEMENT.
+* NEITHER DOES MEDIATEK PROVIDE ANY WARRANTY WHATSOEVER WITH RESPECT TO THE
+* SOFTWARE OF ANY THIRD PARTY WHICH MAY BE USED BY, INCORPORATED IN, OR
+* SUPPLIED WITH THE MEDIATEK SOFTWARE, AND RECEIVER AGREES TO LOOK ONLY TO SUCH
+* THIRD PARTY FOR ANY WARRANTY CLAIM RELATING THERETO. RECEIVER EXPRESSLY ACKNOWLEDGES
+* THAT IT IS RECEIVER'S SOLE RESPONSIBILITY TO OBTAIN FROM ANY THIRD PARTY ALL PROPER LICENSES
+* CONTAINED IN MEDIATEK SOFTWARE. MEDIATEK SHALL ALSO NOT BE RESPONSIBLE FOR ANY MEDIATEK
+* SOFTWARE RELEASES MADE TO RECEIVER'S SPECIFICATION OR TO CONFORM TO A PARTICULAR
+* STANDARD OR OPEN FORUM. RECEIVER'S SOLE AND EXCLUSIVE REMEDY AND MEDIATEK'S ENTIRE AND
+* CUMULATIVE LIABILITY WITH RESPECT TO THE MEDIATEK SOFTWARE RELEASED HEREUNDER WILL BE,
+* AT MEDIATEK'S OPTION, TO REVISE OR REPLACE THE MEDIATEK SOFTWARE AT ISSUE,
+* OR REFUND ANY SOFTWARE LICENSE FEES OR SERVICE CHARGE PAID BY RECEIVER TO
+* MEDIATEK FOR SUCH MEDIATEK SOFTWARE AT ISSUE.
+*/
+
+#include <debug.h>
+#include <err.h>
+#include <string.h>
+#include <stdlib.h>
+#include <kernel/thread.h>
+#include <kernel/timer.h>
+#include <kernel/event.h>
+#include <dev/udc.h>
+#include <platform/mt_typedefs.h>
+#include <platform/mtk_wdt.h>
+#include <version.h>
+#include <verified_boot_common.h>   // for sec_query_warranty()
+#include "sys_commands.h"
+#include <block_generic_interface.h>
+#include <part_interface.h>
+#include <pal_log.h>
+#ifdef MTK_AB_OTA_UPDATER
+#include <bootctrl.h>
+#endif  // MTK_AB_OTA_UPDATER
+
+extern int get_off_mode_charge_status(void);  // FIXME!!! #include <xxx.h>        // for get_off_mode_charge_status()
+
+
+#include "dl_commands.h"
+#include "fastboot.h"
+#ifdef MTK_GPT_SCHEME_SUPPORT
+#include <platform/partition.h>
+#else
+#include <mt_partition.h>
+#endif
+#if defined(MTK_SECURITY_SW_SUPPORT) && defined(MTK_SEC_FASTBOOT_UNLOCK_SUPPORT)
+#include "sec_unlock.h"
+#endif
+#include <platform/boot_mode.h>
+#define MAX_RSP_SIZE 64
+/* MAX_USBFS_BULK_SIZE: if use USB3 QMU GPD mode: cannot exceed 63 * 1024 */
+#define MAX_USBFS_BULK_SIZE (16 * 1024)
+
+#define EXPAND(NAME) #NAME
+#define TARGET(NAME) EXPAND(NAME)
+
+#define USB_CMD_TIMEOUT 5000
+#ifdef SUPPORT_U3
+#include <mt_ssusb.h>
+#endif
+
+static event_t usb_online;
+static event_t txn_done;
+static unsigned char buffer[4096] __attribute__((aligned(64)));
+static char response[MAX_RSP_SIZE] __attribute__((aligned(64)));
+static struct udc_endpoint *in, *out;
+static struct udc_request *req;
+int txn_status;
+
+void *download_base;
+unsigned download_max;
+unsigned download_size;
+extern int sec_usbdl_enabled (void);
+extern void mtk_wdt_disable(void);
+extern void mtk_wdt_restart(void);
+extern unsigned get_secure_status(void);
+extern unsigned get_unlocked_status(void);
+unsigned fastboot_state = STATE_OFFLINE;
+
+extern void fastboot_oem_key(const char *arg, void *data, unsigned sz);
+extern void fastboot_oem_query_lock_state(const char *arg, void *data, unsigned sz);
+
+timer_t wdt_timer;
+struct fastboot_cmd *cmdlist;
+
+extern BOOT_ARGUMENT *g_boot_arg;
+
+extern char sn_buf[];
+extern int get_bat_volt(int times);
+char battery_voltage[6] = "";
+char hw_revision[12] = "";
+char erase_blk_size[12] = "";
+char logical_blk_size[12] = "";
+#define RADIO_VER_LEN 64
+char radio_version[RADIO_VER_LEN+1];
+int modem_image_loaded = 0;
+extern void ccci_load_modem_image(void);
+extern int ccci_get_md_version(int md_id, char buf[], int size);
+
+static void req_complete(struct udc_request *req, unsigned actual, int status)
+{
+	txn_status = status;
+	req->length = actual;
+	event_signal(&txn_done, 0);
+}
+
+void update_device_info()
+{
+	if (sprintf(battery_voltage, "%dmV", get_bat_volt(1)) < 0)
+		dprintf(INFO, "sprintf error in %s:%d\n", __FILE__, __LINE__);
+
+	if (sprintf(hw_revision, "%x", mt_get_chip_hw_ver()) < 0)
+		dprintf(INFO, "sprintf error in %s:%d\n", __FILE__, __LINE__);
+
+#ifndef MNTL_SUPPORT
+	if (sprintf(erase_blk_size, "0x%lx", mt_part_get_erasesz()) < 0)
+		dprintf(INFO, "sprintf error in %s:%d\n", __FILE__, __LINE__);
+
+	if (sprintf(logical_blk_size, "0x%lx", mt_part_get_blksz()) < 0)
+		dprintf(INFO, "sprintf error in %s:%d\n", __FILE__, __LINE__);
+#endif
+}
+
+void update_radio_version()
+{
+	int len = 0;
+
+#ifdef LK_LD_MD_SUPPORT
+	dprintf(INFO, "load modem image in fastboot mode to get radio version\n");
+	ccci_load_modem_image();
+	modem_image_loaded = 1;
+	len = ccci_get_md_version(0, radio_version, RADIO_VER_LEN);
+#endif
+	if (len <= 0) {
+		if (sprintf(radio_version, "N/A") < 0)
+			dprintf(INFO, "sprintf error in %s:%d\n", __FILE__, __LINE__);
+	}
+}
+
+void fastboot_register(const char *prefix, void (*handle)(const char *arg, void *data, unsigned sz),
+					   unsigned allowed_when_security_on, unsigned forbidden_when_lock_on)
+{
+	struct fastboot_cmd *cmd;
+
+	cmd = malloc(sizeof(*cmd));
+	if (cmd) {
+		cmd->prefix = prefix;
+		cmd->prefix_len = strlen(prefix);
+		cmd->allowed_when_security_on = allowed_when_security_on;
+		cmd->forbidden_when_lock_on = forbidden_when_lock_on;
+		cmd->handle = handle;
+		cmd->next = cmdlist;
+		cmdlist = cmd;
+	}
+}
+
+struct fastboot_var *varlist;
+
+void fastboot_publish(const char *name, const char *value)
+{
+	struct fastboot_var *var;
+	var = malloc(sizeof(*var));
+	if (var) {
+		var->name = name;
+		var->value = value;
+		var->next = varlist;
+		varlist = var;
+	}
+}
+
+/* Remove all published variables which name with its length is matched*/
+void fastboot_delete_var(const char *name)
+{
+	struct fastboot_var *var = varlist;
+	struct fastboot_var *var_prev = NULL, *var_remove;
+
+	while (NULL != var) {
+		if (!strncmp(name, var->name, strlen(name))) {
+			if (!var_prev)
+				varlist = varlist->next;
+			else
+				var_prev->next = var->next;
+			var_remove = var;
+			var = var->next;
+			if (var_remove) {
+				free(var_remove);
+				var_remove = NULL;
+			}
+		}
+		else {
+			var_prev = var;
+			var = var->next;
+		}
+	}
+
+	return;
+}
+
+void fastboot_update_var(const char *name, const char *value)
+{
+	struct fastboot_var *var = varlist;
+
+	while (NULL != var) {
+		if (!strcmp(name, var->name)) {
+			var->value = value;
+		}
+		var = var->next;
+	}
+
+	return;
+}
+
+const char *fastboot_get_var(const char *name)
+{
+	struct fastboot_var *var = varlist;
+
+	while (NULL != var) {
+		if (!strcmp(name, var->name)) {
+			return var->value;
+		}
+		var = var->next;
+	}
+
+	return "";
+}
+
+int usb_read(void *_buf, unsigned len)
+{
+	int r;
+	unsigned xfer;
+	unsigned char *buf = _buf;
+	int count = 0;
+
+	if (fastboot_state == STATE_ERROR)
+		goto oops;
+
+	while (len > 0) {
+		xfer = (len > MAX_USBFS_BULK_SIZE) ? MAX_USBFS_BULK_SIZE : len;
+		req->buf = buf;
+		req->length = xfer;
+		req->complete = req_complete;
+		r = udc_request_queue(out, req);
+		if (r < 0) {
+			dprintf(INFO, "usb_read() queue failed\n");
+			goto oops;
+		}
+		event_wait(&txn_done);
+
+		if (txn_status < 0) {
+			dprintf(INFO, "usb_read() transaction failed\n");
+			goto oops;
+		}
+
+		count += req->length;
+		buf += req->length;
+		len -= req->length;
+
+		/* short transfer? */
+		if (req->length != xfer) break;
+	}
+
+	return count;
+
+oops:
+	fastboot_state = STATE_ERROR;
+	return -1;
+}
+
+int usb_read_with_timeout(void *_buf, unsigned len, time_t timeout)
+{
+	int r;
+	unsigned xfer;
+	unsigned char *buf = _buf;
+	int count = 0;
+	status_t ret = NO_ERROR;
+
+	if (fastboot_state == STATE_ERROR)
+		goto oops;
+
+	while (len > 0) {
+		xfer = (len > MAX_USBFS_BULK_SIZE) ? MAX_USBFS_BULK_SIZE : len;
+		req->buf = buf;
+		req->length = xfer;
+		req->complete = req_complete;
+		r = udc_request_queue(out, req);
+		if (r < 0) {
+			dprintf(INFO, "usb_read() queue failed\n");
+			goto oops;
+		}
+		ret = event_wait_timeout(&txn_done, timeout);
+		if (ret != NO_ERROR) {
+			goto oops;
+		}
+		if (txn_status < 0) {
+			dprintf(INFO, "usb_read() transaction failed\n");
+			goto oops;
+		}
+
+		count += req->length;
+		buf += req->length;
+		len -= req->length;
+
+		/* short transfer? */
+		if (req->length != xfer) break;
+	}
+
+	return count;
+
+oops:
+	fastboot_state = STATE_ERROR;
+	return -1;
+}
+
+int usb_write(void *buf, unsigned len)
+{
+	int r;
+
+	if (fastboot_state == STATE_ERROR)
+		goto oops;
+
+	req->buf = buf;
+	req->length = len;
+	req->complete = req_complete;
+	r = udc_request_queue(in, req);
+	if (r < 0) {
+		dprintf(INFO, "usb_write() queue failed\n");
+		goto oops;
+	}
+	event_wait(&txn_done);
+	if (txn_status < 0) {
+		dprintf(INFO, "usb_write() transaction failed\n");
+		goto oops;
+	}
+	return req->length;
+
+oops:
+	fastboot_state = STATE_ERROR;
+	return -1;
+}
+
+int usb_write_with_timeout(void *buf, unsigned len, time_t timeout)
+{
+	int r;
+	status_t ret = NO_ERROR;
+
+	if (fastboot_state == STATE_ERROR)
+		goto oops;
+
+	req->buf = buf;
+	req->length = len;
+	req->complete = req_complete;
+	r = udc_request_queue(in, req);
+	if (r < 0) {
+		dprintf(INFO, "usb_write() queue failed\n");
+		goto oops;
+	}
+	ret = event_wait_timeout(&txn_done, timeout);
+	if (ret != NO_ERROR) {
+		goto oops;
+	}
+	if (txn_status < 0) {
+		dprintf(INFO, "usb_write() transaction failed\n");
+		goto oops;
+	}
+	return req->length;
+
+oops:
+	fastboot_state = STATE_ERROR;
+	return -1;
+}
+
+#ifdef SUPPORT_U3
+void fastboot_reset_usb(void)
+{
+#if defined(USB_RESET_AFTER_SUSPEND)
+	mt_udc_reset(U3D_DFT_SPEED);
+	mt_usb_disconnect_internal();
+	/* soft connect U2 or U3 by g_speed */
+	mt_usb_connect_internal();
+#else
+	mt_usb_disconnect_internal();
+	mu3d_hal_u3dev_connect();
+#endif
+}
+#endif
+
+void fastboot_ack(const char *code, const char *reason)
+{
+	if (fastboot_state != STATE_COMMAND)
+		return;
+
+	if (reason == 0)
+		reason = "";
+
+	memset(response, 0, sizeof(response));
+
+	if (snprintf(response, MAX_RSP_SIZE, "%s%s", code, reason) < 0) {
+		strncpy(response, "unknown error", sizeof(response) - 1);
+		response[sizeof(response) - 1] = '\0';
+	}
+	fastboot_state = STATE_COMPLETE;
+
+	usb_write_with_timeout(response, strlen(response), USB_CMD_TIMEOUT);
+
+}
+
+void fastboot_info(const char *reason)
+{
+	if (fastboot_state != STATE_COMMAND)
+		return;
+
+	if (reason == 0)
+		return;
+
+	memset(response, 0, sizeof(response));
+
+	if (snprintf(response, MAX_RSP_SIZE, "INFO%s", reason) < 0) {
+		strncpy(response, "unknown error", sizeof(response) - 1);
+		response[sizeof(response) - 1] = '\0';
+	}
+
+	usb_write_with_timeout(response, strlen(response), USB_CMD_TIMEOUT);
+}
+
+void fastboot_fail(const char *reason)
+{
+	fastboot_ack("FAIL", reason);
+}
+
+void fastboot_okay(const char *info)
+{
+	fastboot_ack("OKAY", info);
+}
+
+static void fastboot_command_loop(void)
+{
+	struct fastboot_cmd *cmd;
+	int r;
+	dprintf(ALWAYS,"fastboot: processing commands\n");
+
+again:
+	while (fastboot_state != STATE_ERROR) {
+		memset(buffer, 0, sizeof(buffer));
+		r = usb_read(buffer, MAX_RSP_SIZE);
+		if (r < 0) break; //no input command
+		buffer[r] = 0;
+		dprintf(ALWAYS,"[fastboot: command buf]-[%s]-[len=%d]\n", buffer, r);
+		dprintf(ALWAYS,"[fastboot]-[download_base:0x%x]-[download_size:0x%x]\n",(unsigned int)download_base,(unsigned int)download_size);
+
+		/*Pick up matched command and handle it*/
+		for (cmd = cmdlist; cmd; cmd = cmd->next) {
+			fastboot_state = STATE_COMMAND;
+			if (memcmp(buffer, cmd->prefix, cmd->prefix_len)) {
+				continue;
+			}
+
+			dprintf(ALWAYS,"[Cmd process]-[buf:%s]-[lenBuf:%s]\n", buffer,  buffer + cmd->prefix_len);
+#ifdef MTK_SECURITY_SW_SUPPORT
+			extern unsigned int seclib_sec_boot_enabled(unsigned int);
+			//if security boot enable, check cmd allowed
+			if ( !(sec_usbdl_enabled() || seclib_sec_boot_enabled(1)) || cmd->allowed_when_security_on )
+				if ((!cmd->forbidden_when_lock_on) || (0 != get_unlocked_status()))
+#endif
+				{
+					cmd->handle((const char*) buffer + cmd->prefix_len, (void*) download_base, download_size);
+				}
+				if (fastboot_state == STATE_COMMAND) {
+#ifdef MTK_SECURITY_SW_SUPPORT
+					if ((sec_usbdl_enabled() || seclib_sec_boot_enabled(1)) && !cmd->allowed_when_security_on ) {
+						fastboot_fail("not support on security");
+					} else if ((cmd->forbidden_when_lock_on) && (0 == get_unlocked_status())) {
+						fastboot_fail("not allowed in locked state");
+					} else
+#endif
+					{
+						fastboot_fail("unknown reason");
+					}
+				}
+				goto again;
+		}
+		dprintf(ALWAYS,"[unknown command]*[%s]*\n", buffer);
+		fastboot_fail("unknown command");
+
+	}
+	fastboot_state = STATE_OFFLINE;
+	dprintf(ALWAYS,"fastboot: oops!\n");
+}
+
+static int fastboot_handler(void *arg)
+{
+	for (;;) {
+		event_wait(&usb_online);
+		fastboot_command_loop();
+	}
+	return 0;
+}
+
+static void fastboot_notify(struct udc_gadget *gadget, unsigned event)
+{
+	if (event == UDC_EVENT_ONLINE) {
+		event_signal(&usb_online, 0);
+	} else if (event == UDC_EVENT_OFFLINE) {
+		event_unsignal(&usb_online);
+	}
+}
+
+static struct udc_endpoint *fastboot_endpoints[2];
+
+static struct udc_gadget fastboot_gadget = {
+	.notify     = fastboot_notify,
+	.ifc_class  = 0xff,
+	.ifc_subclass   = 0x42,
+	.ifc_protocol   = 0x03,
+	.ifc_endpoints  = 2,
+	.ifc_string = "fastboot",
+	.ept        = fastboot_endpoints,
+};
+
+extern void fastboot_oem_register();
+void register_partition_var(void)
+{
+	int i, buf_len, val_buf_len = 20;
+	unsigned long long p_size;
+	char part_type[] = "partition-type:";
+	char part_size[] = "partition-size:";
+	char *type_buf;
+	char *value_buf;
+	char *var_name_buf;
+	char *p_name_buf;
+	static int is_registered;
+
+	if (is_registered) {
+		fastboot_delete_var(part_type);
+		fastboot_delete_var(part_size);
+	}
+
+	for (i=0; i<PART_MAX_COUNT; i++) {
+		p_size = partition_get_size(i);
+		if ((long long)p_size == -1)
+			continue;
+		partition_get_name(i,&p_name_buf);
+
+		partition_get_type(i,&type_buf);
+
+		buf_len = strlen(part_type) + strlen(p_name_buf)+1;
+		var_name_buf = malloc(buf_len);
+		if (!var_name_buf) {
+			pal_log_info("var_name_buf malloc fails. partition:%s len:%d\n", p_name_buf, buf_len);
+			continue;
+                }
+		if (snprintf(var_name_buf, buf_len, "%s%s", part_type, p_name_buf) < 0) {
+			dprintf(INFO, "snprintf error in %s:%d\n", __FILE__, __LINE__);
+		}
+		else
+			fastboot_publish(var_name_buf,type_buf);
+		//printf("%d %s %s\n",i,var_name_buf,type_buf);
+
+		value_buf = malloc(val_buf_len);
+		if (!value_buf) {
+			pal_log_info("value_buf malloc fails. partition:%s len:%d\n", p_name_buf, val_buf_len);
+			continue;
+		}
+		if (snprintf(value_buf,val_buf_len,"%llx",p_size) < 0) {
+			dprintf(INFO, "snprintf error in %s:%d\n", __FILE__, __LINE__);
+			continue;
+		}
+
+		buf_len = strlen(part_size) + strlen(p_name_buf)+1;
+		var_name_buf = malloc(buf_len);
+		if (!var_name_buf) {
+			pal_log_info("var_name_buf malloc fails. partition:%s len:%d\n", p_name_buf, buf_len);
+			continue;
+                }
+		if (snprintf(var_name_buf, buf_len, "%s%s", part_size, p_name_buf) < 0) {
+			dprintf(INFO, "snprintf error in %s:%d\n", __FILE__, __LINE__);
+			continue;
+		}
+
+		fastboot_publish(var_name_buf,value_buf);
+		//printf("%d %s %s\n",i,var_name_buf,value_buf);
+	}
+
+	is_registered = 1;
+}
+
+/* return value: 1: option is valid, 0: option is invalid */
+static unsigned int is_option_valid(unsigned int lower, unsigned int upper, unsigned int option)
+{
+	if (option < lower)
+		return 0;
+
+	if (option > upper)
+		return 0;
+
+	return 1;
+}
+
+#define NUM_SEC_OPTION (2)
+static void register_secure_unlocked_var(void)
+{
+	static const char str_buf[NUM_SEC_OPTION][4] = {"no","yes"};
+	unsigned secure_status = 0; /* default value is "no" */
+	unsigned unlocked_status = 1; /* default value is "yes" */
+	int warranty = 0; /* default value is "no" */
+
+#ifdef MTK_SECURITY_SW_SUPPORT
+	secure_status = get_secure_status();
+	/* use default value if result is out or range */
+	if (secure_status >= NUM_SEC_OPTION)
+		secure_status = 0;
+
+	/* use default value if result is out or range */
+	unlocked_status = get_unlocked_status();
+	if (unlocked_status >= NUM_SEC_OPTION)
+		unlocked_status = 1;
+
+	sec_query_warranty(&warranty);
+	if (warranty >= NUM_SEC_OPTION)
+		warranty = 0;
+#endif
+
+	if (is_option_valid(0, NUM_SEC_OPTION - 1, secure_status))
+		fastboot_publish("secure", str_buf[secure_status]);
+
+	if (is_option_valid(0, NUM_SEC_OPTION - 1, unlocked_status))
+		fastboot_publish("unlocked", str_buf[unlocked_status]);
+
+	if (is_option_valid(0, NUM_SEC_OPTION - 1, (unsigned int)warranty))
+		fastboot_publish("warranty", str_buf[warranty]);
+
+	return;
+}
+
+#ifdef MTK_OFF_MODE_CHARGE_SUPPORT
+static void register_off_mode_charge_var(void)
+{
+	//INIT VALUE
+	static const char str_buf[2][2] = {"0", "1"};
+	unsigned off_mode_status = 0; /* default value is "0" */
+
+	off_mode_status = get_off_mode_charge_status();
+	if ((off_mode_status == 0) || (off_mode_status == 1))
+		fastboot_publish("off-mode-charge", str_buf[off_mode_status]);
+	else
+		dprintf(INFO, "off mode charge status is out of boundary\n");
+}
+#endif
+
+
+#ifdef MTK_AB_OTA_UPDATER
+/******************************************************************************
+******************************************************************************/
+static char *part_name_array[PART_MAX_COUNT] = {NULL};
+static unsigned int part_name_index = 0;
+
+
+/******************************************************************************
+******************************************************************************/
+static bool is_part_name_processed(char *name)
+{
+	for (unsigned int i = 0; i < PART_MAX_COUNT; i++) {
+		if (!part_name_array[i]) {
+			return false;
+		}
+		int len = strlen(name);
+		if (!strncmp(part_name_array[i], name, len + 1))
+			return true;
+		else
+			continue;
+	}
+	return false;
+}
+
+
+/******************************************************************************
+******************************************************************************/
+static void insert_part_name(char *name)
+{
+	if (part_name_index >= PART_MAX_COUNT)
+		return;
+
+	part_name_array[part_name_index] = name;
+	part_name_index++;
+}
+
+
+/******************************************************************************
+******************************************************************************/
+static void release_part_name(void)
+{
+	for (unsigned int i = 0; i < part_name_index; i++) {
+		free(part_name_array[i]);
+		part_name_array[i] = NULL;
+	}
+}
+
+
+/******************************************************************************
+* This function publishes the following variables: "has-slot", "current-slot",
+* "slot-count", "slot-successful", "slot-unbootable", and "slot-retry-count".
+*
+* Note: The "preloader" partition is the only exception that does not have
+*       "_a" or "_b" suffix even when it supports A/B systems.
+******************************************************************************/
+static void publish_ab_variables(void)
+{
+	char *str_yes = "yes";
+	char *str_no = "no";
+	char *str_yes_or_no = NULL;
+	char *str_slot_count = "2";
+	char *str_has_slot = "has-slot:";
+	const int has_slot_len = strlen(str_has_slot);
+	char *str_successful_a = "slot-successful:a";
+	char *str_successful_b = "slot-successful:b";
+	char *str_unbootable_a = "slot-unbootable:a";
+	char *str_unbootable_b = "slot-unbootable:b";
+	char *str_retry_a = "slot-retry-count:a";
+	char *str_retry_b = "slot-retry-count:b";
+	static char str_retry_count_a[4] = {'\0'};
+	static char str_retry_count_b[4] = {'\0'};
+	char *str_preloader = "has-slot:preloader";
+	const char *ab_suffix = NULL;
+
+	for (int i = 0; i < PART_MAX_COUNT; i++) {
+		char *part_name;
+		int ret = partition_get_name(i, &part_name);
+		if (ret < 0)
+			break;  // early termination
+		int len = has_slot_len + strlen(part_name) + 1;  // include NULL
+		char *new_name = malloc(len);
+		if (!new_name) {
+			release_part_name();
+			dprintf(CRITICAL, "%s (L%d) Error: failed to allocate memory!\n",
+				__func__, __LINE__);
+			return;
+		}
+		if (snprintf(new_name, len, "%s%s", str_has_slot, part_name) < 0) {
+			dprintf(INFO, "snprintf error in %s:%d\n", __FILE__, __LINE__);
+			continue;
+		}
+		if (new_name[len - 3] == '_') {
+			if (new_name[len - 2] == 'a' || new_name[len - 2] == 'b') {
+				str_yes_or_no = str_yes;
+				new_name[len - 3] = '\0';  // truncate suffix
+			}
+		} else {
+			/* Preloader is the only exception that does not have A/B suffix. */
+			if (!strncmp(new_name, str_preloader, strlen(str_preloader))) {
+				if (get_suffix() != NULL)
+					str_yes_or_no = str_yes;
+			} else
+				str_yes_or_no = str_no;
+		}
+		if (!is_part_name_processed(new_name)) {
+			insert_part_name(new_name);
+			fastboot_publish(new_name, str_yes_or_no);
+		}
+	}
+
+	/* current-slot */
+	ab_suffix = get_suffix();
+	if (ab_suffix) {
+		if(!strncmp(ab_suffix, "_", 1))  //remove the under line
+			ab_suffix = ab_suffix+1;
+		fastboot_publish("current-slot", ab_suffix);
+	}
+	else
+		dprintf(INFO, "ab_suffix is null!\n");
+
+	/* slot-count */
+	fastboot_publish("slot-count", str_slot_count);
+
+	int result;
+	/* slot-successful */
+	/* get_bootup_status() returns 1 for successful boot. Otherwise, return 0. */
+	result = get_bootup_status("_a");
+	if (result)
+		str_yes_or_no = str_yes;
+	else
+		str_yes_or_no = str_no;
+	fastboot_publish(str_successful_a, str_yes_or_no);
+
+	result = get_bootup_status("_b");
+	if (result)
+		str_yes_or_no = str_yes;
+	else
+		str_yes_or_no = str_no;
+	fastboot_publish(str_successful_b, str_yes_or_no);
+
+	/* slot-unbootable */
+	/* get_bootable_status() returns -1 for unbootable. Otherwise, return 0. */
+	result = get_bootable_status("_a");
+	if (result <= 0)
+		str_yes_or_no = str_yes;
+	else
+		str_yes_or_no = str_no;
+	fastboot_publish(str_unbootable_a, str_yes_or_no);
+
+	result = get_bootable_status("_b");
+	if (result <= 0)
+		str_yes_or_no = str_yes;
+	else
+		str_yes_or_no = str_no;
+	fastboot_publish(str_unbootable_b, str_yes_or_no);
+
+	/* slot-retry-count */
+	uint8_t retry_count = get_retry_count("_a");
+	if (snprintf(str_retry_count_a, sizeof(str_retry_count_a), "%d", (int)retry_count) < 0)
+		dprintf(INFO, "snprintf error in %s:%d\n", __FILE__, __LINE__);
+	else
+		fastboot_publish(str_retry_a, str_retry_count_a);
+
+	retry_count = get_retry_count("_b");
+	if (snprintf(str_retry_count_b, sizeof(str_retry_count_b), "%d", (int)retry_count) < 0)
+		dprintf(INFO, "snprintf error in %s:%d\n", __FILE__, __LINE__);
+	else
+		fastboot_publish(str_retry_b, str_retry_count_b);
+
+	// release_part_name();  // Do NOT release string here!
+}
+
+#else
+
+static void publish_ab_variables(void)
+{
+	/* slot-count, return 0 for non A/B system */
+	fastboot_publish("slot-count", "0");
+
+}
+
+#endif  // MTK_AB_OTA_UPDATER
+
+
+/******************************************************************************
+******************************************************************************/
+int fastboot_init(void *base, unsigned size)
+{
+	thread_t *thr;
+	int ret;
+	static char dl_max_str[11];  // Take NULL and leading 0x into account. SCRATCH_SIZE must be <= 32-bits
+
+	dprintf(ALWAYS, "fastboot_init()\n");
+
+	download_base = base;
+	download_max = SCRATCH_SIZE;
+	if (snprintf(dl_max_str, sizeof(dl_max_str), "0x%X", download_max) < 0)
+		dprintf(INFO, "snprintf error in %s:%d\n", __FILE__, __LINE__);
+
+	//mtk_wdt_disable(); /*It will re-enable during continue boot*/
+	timer_initialize(&wdt_timer);
+	timer_set_periodic(&wdt_timer, 5000, (timer_callback)mtk_wdt_restart, NULL);
+
+	fastboot_register("getvar:", cmd_getvar, TRUE, FALSE);
+	fastboot_publish("version", "0.5");
+	fastboot_publish("version-preloader", g_boot_arg->pl_version);
+	fastboot_publish("version-bootloader", LK_VER_TAG);
+	update_radio_version();
+	fastboot_publish("version-baseband", (const char *)radio_version);
+	publish_ab_variables();
+	fastboot_publish("is-userspace", "no");
+	fastboot_register("signature", cmd_install_sig, FALSE, TRUE);
+
+#if (defined(MTK_EMMC_SUPPORT) || defined(MTK_UFS_SUPPORT)) && defined(MTK_SPI_NOR_SUPPORT)
+	dprintf(ALWAYS,"Init EMMC device in fastboot mode\n");
+	mmc_legacy_init(1);
+#endif
+	fastboot_register("flash:", cmd_flash_mmc, TRUE, TRUE);
+	fastboot_register("erase:", cmd_erase_mmc, TRUE, TRUE);
+
+	fastboot_register("oem printk-ratelimit", cmd_printk_ratelimit, TRUE, FALSE);
+	fastboot_register("continue", cmd_continue, FALSE, FALSE);
+	fastboot_register("reboot", cmd_reboot, TRUE, FALSE);
+	fastboot_register("reboot-bootloader", cmd_reboot_bootloader, TRUE, FALSE);
+	fastboot_register("reboot-recovery",cmd_reboot_recovery, TRUE, FALSE);
+	fastboot_register("reboot-fastboot",cmd_reboot_fastboot, TRUE, FALSE);
+
+	fastboot_publish("product", PROJECT);
+	fastboot_publish("kernel", "lk");
+	register_secure_unlocked_var();
+#ifdef MTK_OFF_MODE_CHARGE_SUPPORT
+	register_off_mode_charge_var();
+#endif
+	fastboot_publish("serialno", sn_buf);
+
+	register_partition_var();
+
+	update_device_info();
+	fastboot_publish("battery-voltage", (const char *) battery_voltage);
+	fastboot_publish("battery-soc-ok", "yes");
+	fastboot_publish("hw-revision", (const char *) hw_revision);
+	fastboot_publish("erase-block-size", erase_blk_size); //temp. hard code for Zion, 512K bytes
+	fastboot_publish("logical-block-size", logical_blk_size); //temp. hard code for Zion, 512 bytes
+	fastboot_publish("variant", ""); //empty if no variants exist
+
+	/*LXO: Download related command*/
+	fastboot_register("download:", cmd_download, TRUE, FALSE);
+	fastboot_publish("max-download-size", dl_max_str);
+	/*LXO: END!Download related command*/
+
+	fastboot_oem_register();
+#if defined(MTK_SECURITY_SW_SUPPORT)
+	fastboot_register("oem p2u", cmd_oem_p2u, TRUE, FALSE);
+#endif
+#ifdef FASTBOOT_DUMP_LOG
+	fastboot_register("oem dump_pllk_log", cmd_oem_dump_log, TRUE, FALSE);
+#endif
+#ifdef MTK_OFF_MODE_CHARGE_SUPPORT
+	fastboot_register("oem off-mode-charge",cmd_oem_off_mode_charge,FALSE, FALSE);
+#endif
+#if defined(MTK_SECURITY_SW_SUPPORT) && defined(MTK_SEC_FASTBOOT_UNLOCK_SUPPORT)
+	fastboot_register("oem key",fastboot_oem_key,TRUE, FALSE);
+	fastboot_register("oem lks",fastboot_oem_query_lock_state,TRUE, FALSE);
+	/* allowed when secure boot and unlocked */
+	fastboot_register("boot", cmd_boot, TRUE, TRUE);
+	/* command rename */
+	fastboot_register("flashing unlock",fastboot_oem_unlock, TRUE, FALSE);
+	fastboot_register("flashing lock",fastboot_oem_lock, TRUE, FALSE);
+	fastboot_register("flashing get_unlock_ability", fastboot_get_unlock_ability, TRUE, FALSE);
+#endif
+	fastboot_register("oem get_socid", fastboot_get_socid, TRUE, FALSE);
+
+#ifdef MTK_JTAG_SWITCH_SUPPORT
+	/* pin mux switch to ap_jtag */
+	fastboot_register("oem ap_jtag",cmd_oem_ap_jtag, TRUE, FALSE);
+#endif
+#ifdef MTK_TINYSYS_SCP_SUPPORT
+	fastboot_register("oem scp_status", cmd_oem_scp_status, TRUE, FALSE);
+	fastboot_register("oem scp_log_thru_ap_uart", cmd_oem_scp_log_thru_ap_uart, TRUE, FALSE);
+#endif
+#ifdef MTK_USB2JTAG_SUPPORT
+	fastboot_register("oem usb2jtag", cmd_oem_usb2jtag, TRUE, FALSE);
+#endif
+#ifdef MTK_MRDUMP_SUPPORT
+	fastboot_register("oem mrdump", cmd_oem_mrdump, TRUE, FALSE);
+	fastboot_register("oem mrdump-output-set",
+			   cmd_oem_mrdump_outdev, TRUE, FALSE);
+	fastboot_register("oem mrdump-file-allocate",
+			   cmd_oem_mrdump_fallocate, TRUE, FALSE);
+	fastboot_register("oem mrdump_chkimg",
+			   cmd_oem_mrdump_chkimg, TRUE, FALSE);
+#endif
+#ifdef MTK_AB_OTA_UPDATER
+	fastboot_register("set_active:", cmd_set_active, TRUE, FALSE);
+#endif
+
+#ifdef MTK_ULTRA_FLASH
+	fastboot_register("oem ultraflash:", cmd_oem_ultra_flash, TRUE, TRUE);
+	fastboot_register("oem ultraflash_en", cmd_oem_ultra_flash_en, TRUE, TRUE);
+	fastboot_register("ultraflash:", cmd_oem_ultra_flash, TRUE, TRUE);
+#endif
+	event_init(&usb_online, 0, EVENT_FLAG_AUTOUNSIGNAL);
+	event_init(&txn_done, 0, EVENT_FLAG_AUTOUNSIGNAL);
+
+	in = udc_endpoint_alloc(UDC_TYPE_BULK_IN, 512);
+	if (!in) {
+		ret = -1;
+		goto fail_alloc_in;
+	}
+
+	out = udc_endpoint_alloc(UDC_TYPE_BULK_OUT, 512);
+	if (!out) {
+		ret = -2;
+		goto fail_alloc_out;
+	}
+
+	fastboot_endpoints[0] = in;
+	fastboot_endpoints[1] = out;
+
+	req = udc_request_alloc();
+	if (!req) {
+		ret = -3;
+		goto fail_alloc_req;
+	}
+
+	if (udc_register_gadget(&fastboot_gadget)) {
+		ret = -4;
+		goto fail_udc_register;
+	}
+
+	thr = thread_create("fastboot", fastboot_handler, 0, DEFAULT_PRIORITY, DEFAULT_STACK_SIZE);
+	if (!thr) {
+		ret = -1;
+		goto fail_alloc_in;
+	}
+	thread_resume(thr);
+	return 0;
+
+fail_udc_register:
+	udc_request_free(req);
+fail_alloc_req:
+	udc_endpoint_free(out);
+fail_alloc_out:
+	udc_endpoint_free(in);
+fail_alloc_in:
+	dprintf(CRITICAL, "%s fail: %d\n", __func__, ret);
+	ASSERT(0);
+	return ret;
+}
+

+ 67 - 0
app/mt_boot/fastboot.h

@@ -0,0 +1,67 @@
+/* Copyright Statement:
+*
+* This software/firmware and related documentation ("MediaTek Software") are
+* protected under relevant copyright laws. The information contained herein
+* is confidential and proprietary to MediaTek Inc. and/or its licensors.
+* Without the prior written permission of MediaTek inc. and/or its licensors,
+* any reproduction, modification, use or disclosure of MediaTek Software,
+* and information contained herein, in whole or in part, shall be strictly prohibited.
+*/
+/* MediaTek Inc. (C) 2015. All rights reserved.
+*
+* BY OPENING THIS FILE, RECEIVER HEREBY UNEQUIVOCALLY ACKNOWLEDGES AND AGREES
+* THAT THE SOFTWARE/FIRMWARE AND ITS DOCUMENTATIONS ("MEDIATEK SOFTWARE")
+* RECEIVED FROM MEDIATEK AND/OR ITS REPRESENTATIVES ARE PROVIDED TO RECEIVER ON
+* AN "AS-IS" BASIS ONLY. MEDIATEK EXPRESSLY DISCLAIMS ANY AND ALL WARRANTIES,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED WARRANTIES OF
+* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE OR NONINFRINGEMENT.
+* NEITHER DOES MEDIATEK PROVIDE ANY WARRANTY WHATSOEVER WITH RESPECT TO THE
+* SOFTWARE OF ANY THIRD PARTY WHICH MAY BE USED BY, INCORPORATED IN, OR
+* SUPPLIED WITH THE MEDIATEK SOFTWARE, AND RECEIVER AGREES TO LOOK ONLY TO SUCH
+* THIRD PARTY FOR ANY WARRANTY CLAIM RELATING THERETO. RECEIVER EXPRESSLY ACKNOWLEDGES
+* THAT IT IS RECEIVER'S SOLE RESPONSIBILITY TO OBTAIN FROM ANY THIRD PARTY ALL PROPER LICENSES
+* CONTAINED IN MEDIATEK SOFTWARE. MEDIATEK SHALL ALSO NOT BE RESPONSIBLE FOR ANY MEDIATEK
+* SOFTWARE RELEASES MADE TO RECEIVER'S SPECIFICATION OR TO CONFORM TO A PARTICULAR
+* STANDARD OR OPEN FORUM. RECEIVER'S SOLE AND EXCLUSIVE REMEDY AND MEDIATEK'S ENTIRE AND
+* CUMULATIVE LIABILITY WITH RESPECT TO THE MEDIATEK SOFTWARE RELEASED HEREUNDER WILL BE,
+* AT MEDIATEK'S OPTION, TO REVISE OR REPLACE THE MEDIATEK SOFTWARE AT ISSUE,
+* OR REFUND ANY SOFTWARE LICENSE FEES OR SERVICE CHARGE PAID BY RECEIVER TO
+* MEDIATEK FOR SUCH MEDIATEK SOFTWARE AT ISSUE.
+*/
+
+#ifndef __FASTBOOT_H
+#define __FASTBOOT_H
+
+#define STATE_OFFLINE   0
+#define STATE_COMMAND   1
+#define STATE_COMPLETE  2
+#define STATE_ERROR 3
+
+struct fastboot_cmd {
+	struct fastboot_cmd *next;
+	const char *prefix;
+	unsigned prefix_len;
+	unsigned allowed_when_security_on;
+	unsigned forbidden_when_lock_on;
+	void (*handle)(const char *arg, void *data, unsigned sz);
+};
+
+struct fastboot_var {
+	struct fastboot_var *next;
+	const char *name;
+	const char *value;
+};
+
+void fastboot_okay(const char *info);
+void fastboot_fail(const char *reason);
+void fastboot_register(const char *prefix, void (*handle)(const char *arg, void *data, unsigned sz),
+                       unsigned allowed_when_security_on, unsigned forbidden_when_lock_on);
+
+void fastboot_info(const char *reason);
+void fastboot_publish(const char *name, const char *value);
+void fastboot_update_var(const char *name, const char *value);
+const char *fastboot_get_var(const char *name);
+void fastboot_get_socid(const char *arg, void *data, unsigned sz);
+
+void register_partition_var(void);
+#endif

+ 1025 - 0
app/mt_boot/fdt_op.c

@@ -0,0 +1,1025 @@
+/* Copyright Statement:
+*
+* This software/firmware and related documentation ("MediaTek Software") are
+* protected under relevant copyright laws. The information contained herein
+* is confidential and proprietary to MediaTek Inc. and/or its licensors.
+* Without the prior written permission of MediaTek inc. and/or its licensors,
+* any reproduction, modification, use or disclosure of MediaTek Software,
+* and information contained herein, in whole or in part, shall be strictly prohibited.
+*/
+/* MediaTek Inc. (C) 2018. All rights reserved.
+*
+* BY OPENING THIS FILE, RECEIVER HEREBY UNEQUIVOCALLY ACKNOWLEDGES AND AGREES
+* THAT THE SOFTWARE/FIRMWARE AND ITS DOCUMENTATIONS ("MEDIATEK SOFTWARE")
+* RECEIVED FROM MEDIATEK AND/OR ITS REPRESENTATIVES ARE PROVIDED TO RECEIVER ON
+* AN "AS-IS" BASIS ONLY. MEDIATEK EXPRESSLY DISCLAIMS ANY AND ALL WARRANTIES,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED WARRANTIES OF
+* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE OR NONINFRINGEMENT.
+* NEITHER DOES MEDIATEK PROVIDE ANY WARRANTY WHATSOEVER WITH RESPECT TO THE
+* SOFTWARE OF ANY THIRD PARTY WHICH MAY BE USED BY, INCORPORATED IN, OR
+* SUPPLIED WITH THE MEDIATEK SOFTWARE, AND RECEIVER AGREES TO LOOK ONLY TO SUCH
+* THIRD PARTY FOR ANY WARRANTY CLAIM RELATING THERETO. RECEIVER EXPRESSLY ACKNOWLEDGES
+* THAT IT IS RECEIVER'S SOLE RESPONSIBILITY TO OBTAIN FROM ANY THIRD PARTY ALL PROPER LICENSES
+* CONTAINED IN MEDIATEK SOFTWARE. MEDIATEK SHALL ALSO NOT BE RESPONSIBLE FOR ANY MEDIATEK
+* SOFTWARE RELEASES MADE TO RECEIVER'S SPECIFICATION OR TO CONFORM TO A PARTICULAR
+* STANDARD OR OPEN FORUM. RECEIVER'S SOLE AND EXCLUSIVE REMEDY AND MEDIATEK'S ENTIRE AND
+* CUMULATIVE LIABILITY WITH RESPECT TO THE MEDIATEK SOFTWARE RELEASED HEREUNDER WILL BE,
+* AT MEDIATEK'S OPTION, TO REVISE OR REPLACE THE MEDIATEK SOFTWARE AT ISSUE,
+* OR REFUND ANY SOFTWARE LICENSE FEES OR SERVICE CHARGE PAID BY RECEIVER TO
+* MEDIATEK FOR SUCH MEDIATEK SOFTWARE AT ISSUE.
+*/
+#include <stdio.h>
+#include <stdlib.h>
+#include <stddef.h>
+#include <assert.h>
+#include <bootargs.h>
+#include <errno.h>
+#include <string.h>
+#include <pal_assert.h>
+#include <pal_typedefs.h>
+#include <pal_log.h>
+#include <memory_layout.h>
+#include <libfdt.h>
+#include <profiling.h>
+#include <odm_mdtbo.h>
+#include <boot_opt.h>
+#include <boot_info.h>
+#include <part_interface.h>
+#include <ufdt_overlay.h>
+#include <fdt_op.h>
+#include <bootimg.h>
+#include <mt_boot.h>
+#include <arch/arm/mmu.h>
+#include <load_vfy_boot.h>
+#include <mt_rtc.h>
+#include <part_interface.h>
+#include <part_status.h>
+#include <mkimg.h>
+#include <platform/mt_gpt.h>
+#include <odm_mdtbo.h>
+#include <boot_info.h>
+#include <platform/errno.h>
+#include <lk_builtin_dtb.h>
+#include <platform/verified_boot.h>
+#include <target.h>
+#include <recovery.h>
+
+#ifndef LK_MAIN_DTB_BUILT_IN
+void *g_fdt;
+#else
+static void *g_fdt;
+#endif
+DTBO_SRC g_dtbo_load_src = DTBO_FROM_STANDALONE;
+extern u32 g_64bit_dtb_size;
+extern int g_is_64bit_kernel;
+extern char *p_AB_suffix;
+
+
+#define DTBO_PART_NEW_A_NAME "dtbo_a"
+
+static char *dtbo_one_part_name = "dtbo";
+#ifndef MTK_AB_OTA_UPDATER
+static char *dtbo_part_names[] = {"dtbo1", "dtbo2"};
+#endif
+static char *dtbo_fallback_part_name= "odmdtbo";
+static char dtbo_part_name_full[DTBO_PART_NAME_LEN + 1];
+
+extern int mboot_recovery_load_raw_part(char *part_name, unsigned long *addr, unsigned int size);
+extern int mboot_common_load_part(char *part_name, char *img_name, unsigned long addr);
+
+DTBO_SRC get_dtbo_src(void)
+{
+	return g_dtbo_load_src;
+}
+
+void setup_kernel_fdt(void *fdt)
+{
+	g_fdt = fdt;
+}
+void *get_kernel_fdt(void)
+{
+	return g_fdt;
+}
+/***********************************************************************
+* API to retrieve where dtbo partition from, the name is fallback iterated
+************************************************************************/
+char *get_dtbo_part_name(void)
+{
+	char *part_name = NULL;
+	static uint32_t dtbo_part_name_inited = 0;
+
+	if (!dtbo_part_name_inited) {
+#ifdef MTK_AB_OTA_UPDATER
+		part_name = dtbo_part_name_full;
+		if (partition_exists(DTBO_PART_NEW_A_NAME) == PART_OK)
+			strncpy(part_name,dtbo_one_part_name, DTBO_PART_NAME_LEN);
+		else
+			strncpy(part_name, dtbo_fallback_part_name, DTBO_PART_NAME_LEN);
+		part_name[DTBO_PART_NAME_LEN] = '\0';
+		int part_name_len = strlen(part_name);
+		if (p_AB_suffix) {
+			strncpy((void *)&part_name[part_name_len], (void *)p_AB_suffix,
+				DTBO_PART_NAME_LEN - part_name_len);
+		}
+#else
+		int i;
+		int array_size = (int)(sizeof(dtbo_part_names) / sizeof(dtbo_part_names[0]));
+
+		/* check "dtbo" */
+		if (partition_exists(dtbo_one_part_name) == PART_OK) {
+			part_name = dtbo_one_part_name;
+			goto partname_selected;
+		}
+		/* check "dtbo1" */
+		if (partition_exists(dtbo_part_names[0]) == PART_OK) {
+			for (i = 0; i < array_size; i++) {
+				if (partition_get_active_bit_by_name(dtbo_part_names[i]))
+					part_name = dtbo_part_names[i];
+			}
+			if(part_name == NULL)
+				part_name = dtbo_part_names[0];
+		} else
+			/* Fallback to old style */
+			part_name = dtbo_fallback_part_name;
+partname_selected:
+		strncpy(dtbo_part_name_full, part_name, DTBO_PART_NAME_LEN);
+#endif
+		dtbo_part_name_full[DTBO_PART_NAME_LEN] = '\0';
+		dtbo_part_name_inited = 1;
+	}
+	return dtbo_part_name_full;
+}
+
+#if defined(MTK_DCONFIG_SUPPORT)
+
+#define DCONFIG_DTB_SIZE 131072
+#define DCONFIG_PART "boot_para"
+#define DCONFIG_DT_NAME "dconfig-dt"
+
+static u8 *dtb_dconfig_load(void)
+{
+	static bool dconfig_dtb_failed = false;
+	u8 *dconfig_dtb = NULL;
+	int len = 0;
+
+	if (dconfig_dtb_failed) {
+		pal_log_info("dconfig-dt already load failed, don't do it again\n");
+		return NULL;
+	}
+
+#ifdef MTK_SECURITY_SW_SUPPORT
+	unsigned int policy_entry_idx = 0;
+	unsigned int img_auth_required = 0;
+
+	policy_entry_idx = get_policy_entry_idx(DCONFIG_PART);
+	img_auth_required = get_vfy_policy(policy_entry_idx);
+	if (img_auth_required) {
+		uint32_t sec_ret = sec_img_auth_init(DCONFIG_PART, DCONFIG_DT_NAME, 0);
+		if (sec_ret) {
+			dconfig_dtb_failed = true;
+			pal_log_err("dconfig image cert verify failed\n");
+			return NULL;
+		}
+	}
+#endif
+	dconfig_dtb = malloc(DCONFIG_DTB_SIZE);
+	if (dconfig_dtb == NULL) {
+		dconfig_dtb_failed = true;
+		pal_log_err("Not enough memory\n");
+		return NULL;
+	}
+	len = mboot_common_load_part(DCONFIG_PART, DCONFIG_DT_NAME,
+				     (unsigned long)dconfig_dtb);
+	if (len <= 0) {
+		dconfig_dtb_failed = true;
+		pal_log_info("partition_read failed, return value %d\n", len);
+		free(dconfig_dtb);
+		return NULL;
+	}
+#ifdef MTK_SECURITY_SW_SUPPORT
+	if (img_auth_required) {
+		uint32_t sec_ret = sec_img_auth(dconfig_dtb, len);
+		if (sec_ret) {
+			dconfig_dtb_failed = true;
+			pal_log_err("dconfig image verify failed\n");
+			free(dconfig_dtb);
+			return NULL;
+		}
+	}
+#endif
+	return dconfig_dtb;
+}
+
+bool dtb_dconfig_overlay(void *target_fdt)
+{
+	int ret = 0;
+
+	if (target_fdt == NULL) {
+		pal_log_err("dconfig: passing target fdt with null\n");
+		return TRUE;
+	}
+
+	u8 *dconfig_dtb = dtb_dconfig_load();
+	if (dconfig_dtb == NULL) {
+		return TRUE;
+	}
+
+	struct fdt_header *dconfig_fdth = (struct fdt_header *) dconfig_dtb;
+	if (fdt_magic(dconfig_fdth) != FDT_MAGIC) {
+		pal_log_info("FDT magic number miss match : magic %x\n",
+			     fdt_magic(dconfig_fdth));
+		free(dconfig_dtb);
+		return TRUE;
+	}
+	if (fdt_totalsize(dconfig_fdth) >= DCONFIG_DTB_SIZE) {
+		pal_log_err("Dconfig's DT size too large %d\n", fdt_totalsize(dconfig_fdth));
+		free(dconfig_dtb);
+		return TRUE;
+	}
+
+	struct fdt_header *blob = ufdt_install_blob(target_fdt, DTB_MAX_SIZE);
+	if (!blob) {
+		pal_log_err("ufdt_install_blob() failed\n");
+		free(dconfig_dtb);
+		return FALSE;
+	}
+
+	void *merged_fdt = ufdt_apply_overlay(blob, fdt_totalsize(blob), dconfig_fdth,
+					      fdt_totalsize(dconfig_fdth));
+	if (!merged_fdt) {
+		pal_log_err("dconfig: ufdt_apply_overlay failed\n");
+		free(dconfig_dtb);
+		return FALSE;
+	}
+
+	ret = fdt_pack(merged_fdt);
+	if (ret) {
+		pal_log_err("dconfig: fdt_pack failed\n");
+		free(merged_fdt);
+		free(dconfig_dtb);
+		return FALSE;
+	}
+
+	int merged_size = fdt_totalsize(merged_fdt);
+	if (merged_size > DTB_MAX_SIZE) {
+		pal_log_err("dconfig: merged size %d > DTB_MAX_SIZE\n", merged_size);
+		free(merged_fdt);
+		free(dconfig_dtb);
+		return FALSE;
+	}
+
+	if (fdt_open_into(merged_fdt, target_fdt, DTB_MAX_SIZE) != 0) {
+		pal_log_err("dconfig: DTB replace failed\n");
+		free(merged_fdt);
+		free(dconfig_dtb);
+		return FALSE;
+	}
+
+	free(merged_fdt);
+	free(dconfig_dtb);
+	return TRUE;
+}
+
+#else
+
+bool dtb_dconfig_overlay(void *target_fdt)
+{
+	return TRUE;
+}
+
+#endif
+
+#ifndef LK_MAIN_DTB_BUILT_IN
+void *get_lk_overlayed_dtb(void){return g_fdt;}
+
+int32_t prepare_kernel_dtb(void){return 0;}
+
+/***********************************************************************
+* Done after bldr_load_dtb, overlay from associated dtbo partition
+************************************************************************/
+bool dtb_overlay(void *fdt, int size, uint64_t recovery_dtbo_offset)
+{
+	size_t overlay_len = 0;
+	char *part_name = NULL;
+
+	g_fdt = fdt;
+
+	if (fdt == NULL) {
+		pal_log_err("fdt is NULL\n");
+		return FALSE;
+	}
+	if (size == 0) {
+		pal_log_err("fdt size is zero\n");
+		return FALSE;
+	}
+
+#ifdef MTK_AB_OTA_UPDATER
+	part_name = get_dtbo_part_name();
+#else
+	/* for non-AB supporting bootimg hdr version 1, get dtbo from recovery */
+	if (recovery_dtbo_offset == 0) {
+		part_name = get_dtbo_part_name();
+	}
+	else {
+		part_name = "recovery";
+		g_dtbo_load_src = DTBO_FROM_RECOVERY;
+	}
+#endif  // MTK_AB_OTA_UPDATER
+
+	// Note: A buffer is allocated in load_overlay_dtbo() to store the loaded
+	//       odm dtb.
+	char *overlay_buf = load_overlay_dtbo(part_name, &overlay_len, (uint64_t)recovery_dtbo_offset);
+
+	// check overlay dtbo
+	if (overlay_buf == NULL) {
+		pal_log_err("load overlay dtbo failed !\n");
+		return FALSE;
+	}
+
+	// check len of overlay dtbo
+	if (overlay_len == 0) {
+		pal_log_err("size of overlay dtbo is 0 !\n");
+		free(overlay_buf);
+		return FALSE;
+	}
+
+	struct fdt_header *fdth = (struct fdt_header *)g_fdt;
+	fdth->totalsize = cpu_to_fdt32(size);
+
+	int ret = fdt_open_into(g_fdt, g_fdt, size);
+	if (ret) {
+		pal_log_err("fdt_open_into failed \n");
+		free(overlay_buf);
+		return FALSE;
+	}
+	ret = fdt_check_header(g_fdt);
+	if (ret) {
+		pal_log_err("fdt_check_header check failed !\n");
+		free(overlay_buf);
+		return FALSE;
+	}
+
+	char *base_buf = fdt;
+	size_t blob_len = size;
+	struct fdt_header *blob = ufdt_install_blob(base_buf, blob_len);
+	if (!blob) {
+		pal_log_err("ufdt_install_blob() failed!\n");
+		free(overlay_buf);
+		return FALSE;
+	}
+	pal_log_info("blob_len: 0x%x, overlay_len: 0x%x\n", blob_len, overlay_len);
+
+	void *merged_fdt = NULL;
+	PROFILING_START("Overlay");
+	// Note: A buffer is allocated in ufdt_apply_overlay() to store the merge
+	//       device tree.
+	merged_fdt = ufdt_apply_overlay(blob, blob_len, overlay_buf, overlay_len);
+	if (!merged_fdt) {
+		pal_log_err("ufdt_apply_overlay() failed!\n");
+		free(overlay_buf);
+		assert(0);
+		return FALSE;
+	}
+	PROFILING_END();
+
+	// Compact the merged device tree so that the size of the device tree can
+	// be known.
+	ret = fdt_pack(merged_fdt);
+	if (ret) {
+		pal_log_err("fdt_pack(merged_fdt) failed !\n");
+		free(merged_fdt);
+		free(overlay_buf);
+		return FALSE;
+	}
+
+
+	int merged_size = fdt_totalsize(merged_fdt);
+	pal_log_info("fdt merged_size: %d\n", merged_size);
+	if (merged_size > DTB_MAX_SIZE) {
+		pal_log_err("Error: merged size %d > DTB_MAX_SIZE!\n", merged_size);
+		free(merged_fdt);
+		free(overlay_buf);
+		return FALSE;
+	}
+
+	// The memory pointed to by "g_fdt" is the location that the Linux kernel
+	// expects to find the device tree, and it is at least a few mega-bytes
+	// free. The merged device tree is therefore copied to that space.
+	memcpy(g_fdt, merged_fdt, merged_size);
+
+	// Make the totalsize of the device tree larger so that properties can
+	// be inserted into the device tree.
+	((struct fdt_header *)g_fdt)->totalsize = cpu_to_fdt32(DTB_MAX_SIZE);
+
+	free(merged_fdt);
+	free(overlay_buf);
+
+	return TRUE;
+}
+
+
+/*******************************************************************
+* mmap fdt buffer and sanity check it before doing any operation
+********************************************************************/
+bool setup_fdt(void *fdt, int size)
+{
+	int ret;
+	g_fdt = fdt;
+#ifdef MTK_3LEVEL_PAGETABLE
+	u32 addr = (u32)fdt;
+	arch_mmu_map((uint64_t)ROUNDDOWN(addr, PAGE_SIZE),
+		(uint32_t)ROUNDDOWN(addr, PAGE_SIZE),
+		MMU_MEMORY_TYPE_NORMAL_WRITE_BACK | MMU_MEMORY_AP_P_RW_U_NA,
+		ROUNDUP(size, PAGE_SIZE));
+#endif
+	ret = fdt_open_into(g_fdt, g_fdt, size); //DTB maximum size is 2MB
+	if (ret) return FALSE;
+	ret = fdt_check_header(g_fdt);
+	if (ret) return FALSE;
+	return TRUE;
+}
+
+/**************************************************************************
+* Load dtb from boot/recovery, does MMU map and relocate
+***************************************************************************/
+int bldr_load_dtb_from_boot(char *part_name, u32 *dtb_final_addr, uint64_t *recovery_dtbo_offset)
+{
+	int ret = 0;
+	char *ptr;
+	char *dtb_sz;
+	u32 zimage_addr, zimage_size, dtb_size, addr, tmp;
+	u32 dtb_addr = 0;
+	u32 offset = 0;
+	unsigned char *magic;
+	struct bootimg_hdr *p_boot_hdr;
+
+	ptr = malloc(DTB_MAX_SIZE);
+	if (ptr == NULL) {
+		pal_log_err("dtb malloc failed!\n");
+		return -1;
+	}
+
+	//load boot hdr
+	ret = mboot_recovery_load_raw_part(part_name, (unsigned long *)ptr,
+					sizeof(struct bootimg_hdr) + 0x800);
+	if (ret < 0) {
+		pal_log_err("mboot_recovery_load_raw_part(%s, %d) failed, ret: 0x%x\n",
+			part_name, sizeof(struct bootimg_hdr) + 0x800, ret);
+		goto _end;
+	}
+
+	if (0 == bootimg_hdr_valid((uint8_t *)ptr)) {
+		pal_log_err("bootimg_hdr_valid failed\n");
+		ret = -1;
+		goto _end;
+	}
+
+	p_boot_hdr = (void *)ptr;
+	*dtb_final_addr = p_boot_hdr->tags_addr;
+
+	/* Under recovery, get dtbo info from bootimg hdr version 1 */
+	if (!strcmp(part_name, "recovery")) {
+		if (p_boot_hdr->header_version >= BOOT_HEADER_VERSION_ONE) {
+			*recovery_dtbo_offset = (uint64_t)p_boot_hdr->recovery_dtbo_offset;
+			pal_log_err("bldr_load_dtb: recovery_dtbo_offset = 0x%llx\n", (uint64_t)*recovery_dtbo_offset);
+			/* If offset is 0, implies dtbo in its standalone partition */
+			/* In that case, recovery is not self-sufficient */
+			if (*recovery_dtbo_offset == 0)
+				pal_log_err("Warning: check recovery dtbo location!\n");
+		}
+	}
+
+	/* Claim the DT/kernel/ramdisk addr from mblock */
+	mboot_allocate_bootimg_from_mblock(p_boot_hdr);
+
+	/* decide whether this is 64bit kernel from cmdline */
+	platform_parse_bootopt(p_boot_hdr->cmdline);
+
+	if (p_boot_hdr->header_version >= BOOT_HEADER_VERSION_TWO) {
+		dtb_size = p_boot_hdr->dtb_size;
+		tmp = p_boot_hdr->page_sz
+			+ ROUNDUP(p_boot_hdr->kernel_sz, p_boot_hdr->page_sz)
+			+ ROUNDUP(p_boot_hdr->ramdisk_sz, p_boot_hdr->page_sz)
+			+ ROUNDUP(p_boot_hdr->second_sz, p_boot_hdr->page_sz)
+			+ ROUNDUP(p_boot_hdr->recovery_dtbo_size, p_boot_hdr->page_sz);
+
+		if (dtb_size == 0) {
+			pal_log_err("can't find v2 dtb\n");
+			ret = -1;
+			goto _end;
+		}
+
+		ret = partition_read(part_name, (off_t)tmp, (u8 *)ptr,
+			(size_t)ROUNDUP(dtb_size, p_boot_hdr->page_sz));
+		if (ret < 0) {
+			pal_log_err("partition_read for v2 dtb failed, ret: 0x%x\n", ret);
+			goto _end;
+		}
+
+		/* Check dtb format comes with mkdtimg (table_header+table_entry+fdt_body) */
+		if (DT_TABLE_MAGIC == fdt_magic(ptr))
+		{
+			struct dt_table_header *hdr = (struct dt_table_header *)ptr;
+			uint32_t dt_entry_count = fdt32_to_cpu(hdr->dt_entry_count);
+			dtb_addr = (u32)ptr + sizeof(struct dt_table_header)
+				+ dt_entry_count * sizeof(struct dt_table_entry);
+
+			pal_log_err("find v2 dtb with mkdtimg format, dtb file offset: 0x%x\n", tmp);
+		}
+		else if (FDT_MAGIC == fdt_magic(ptr))
+		{
+			dtb_addr = (u32)ptr;
+			pal_log_err("find v2 dtb with fdt format only, dtb file offset: 0x%x\n", tmp);
+		}
+
+		goto _dt_relocate;
+	}
+
+	if (!g_is_64bit_kernel) {
+		//Offset into zImage    Value   Description
+		//0x24  0x016F2818  Magic number used to identify this is an ARM Linux zImage
+		//0x28  start address   The address the zImage starts at
+		//0x2C  end address The address the zImage ends at
+		/* bootimg header size is 0x800, the kernel img text is next to the header */
+		zimage_addr = (u32)ptr + p_boot_hdr->page_sz;
+		if (*(unsigned int *)((unsigned int)zimage_addr) == MKIMG_MAGIC) {
+			zimage_addr += MKIMG_HDR_SZ;
+			offset += MKIMG_HDR_SZ;
+		}
+		zimage_size = *(unsigned int *)((unsigned int)zimage_addr + 0x2c) -
+			*(unsigned int *)((unsigned int)zimage_addr + 0x28);
+		//dtb_addr = (unsigned int)zimage_addr + zimage_size;
+		offset += (p_boot_hdr->page_sz + zimage_size);
+		tmp = ROUNDDOWN(offset, p_boot_hdr->page_sz);
+		ret = partition_read(part_name, (off_t)tmp, (u8 *)ptr, (size_t)DTB_MAX_SIZE);
+		if (ret < 0) {
+			pal_log_err("partition_read failed, ret: 0x%x\n", ret);
+			goto _end;
+		}
+		dtb_addr = (u32)ptr + offset - tmp;
+		dtb_size = fdt32_to_cpu(*(unsigned int *)(ptr + (offset - tmp) + 0x4));
+	} else {
+		/* bootimg header size is 0x800, the kernel img text is next to the header */
+		int i;
+		zimage_size = p_boot_hdr->kernel_sz;
+		offset = p_boot_hdr->page_sz + p_boot_hdr->kernel_sz - DTB_MAX_SIZE;
+		tmp = ROUNDUP(offset, p_boot_hdr->page_sz);
+		ret = partition_read(part_name, (off_t)tmp, (u8 *)ptr, (size_t)DTB_MAX_SIZE);
+		if (ret < 0) {
+			pal_log_err("partition_read failed, ret: 0x%x\n", ret);
+			goto _end;
+		}
+		dtb_addr = 0;
+		dtb_size = 0;
+		addr = (u32)ptr + DTB_MAX_SIZE - 4;
+		for (i = 0; i < (DTB_MAX_SIZE - 4); i++, addr--) {
+			//FDT_MAGIC 0xd00dfeed
+			//dtb append after image.gz may not 4 byte alignment
+			magic = (unsigned char *)addr;
+			if (*(magic + 3) == 0xED && *(magic + 2) == 0xFE &&
+				*(magic + 1) == 0x0D && *(magic + 0) == 0xD0) {
+				dtb_addr = addr;
+				break;
+			}
+		}
+		if (dtb_addr == 0) {
+			pal_log_err("can't find dtb\n");
+			ret = -1;
+			goto _end;
+		}
+		dtb_sz = (char *)(dtb_addr + 4);
+		dtb_size = *(dtb_sz) * 0x1000000 + *(dtb_sz + 1) * 0x10000 +
+			*(dtb_sz + 2) * 0x100 + *(dtb_sz + 3);
+		g_64bit_dtb_size = dtb_size;
+		pal_log_err("Kernel(%d) zimage_size:0x%x,dtb_addr:0x%x(dtb_size:0x%x)\n",
+			g_is_64bit_kernel, zimage_size, dtb_addr, dtb_size);
+	}
+
+_dt_relocate:
+	if (dtb_size > DTB_MAX_SIZE) {
+		pal_log_err("dtb_size too large: 0x%x\n", dtb_size);
+		ret = -1;
+		goto _end;
+	}
+
+#ifdef MTK_3LEVEL_PAGETABLE
+	arch_mmu_map((uint64_t)ROUNDDOWN(*dtb_final_addr, PAGE_SIZE),
+		(uint32_t)ROUNDDOWN(*dtb_final_addr, PAGE_SIZE),
+		MMU_MEMORY_TYPE_NORMAL_WRITE_BACK | MMU_MEMORY_AP_P_RW_U_NA,
+		ROUNDUP(dtb_size, PAGE_SIZE));
+#endif
+	pal_log_err("Copy DTB from 0x%x to 0x%x(size: 0x%x)\n", dtb_addr,
+		*dtb_final_addr, dtb_size);
+	memcpy((void *)*dtb_final_addr, (void *)dtb_addr, dtb_size);
+
+_end:
+	free(ptr);
+	return ret;
+}
+
+/**************************************************************************
+* Please refer to bootimg.h for boot image header structure.
+* bootimg header size is 0x800, the kernel img text is next to the header
+***************************************************************************/
+int bldr_load_dtb(char *boot_load_partition)
+{
+	int ret = 0;
+	u32 dtb_final_addr;
+	char part_name[16];
+	uint64_t recovery_dtbo_offset = 0;
+
+#ifdef MTK_AB_OTA_UPDATER
+	/* no more recovery partition in A/B system update, instead choose boot_a or boot_b */
+	snprintf(part_name, sizeof(part_name), "boot%s", p_AB_suffix);
+#else
+	snprintf(part_name, sizeof(part_name), "%s", boot_load_partition);
+#endif
+
+	/* load dtb from boot */
+	ret = bldr_load_dtb_from_boot(part_name, &dtb_final_addr, &recovery_dtbo_offset);
+	if (ret < 0)
+		return ret;
+
+	// Place setup_fdt() after bldr_load_dtb() because it sets "fdt_header->totalsize".
+	ret = setup_fdt((void *)dtb_final_addr, DTB_MAX_SIZE);
+	pal_log_err("[LK] fdt setup addr:0x%x status:%d!!!\n", dtb_final_addr, ret);
+	if (ret == FALSE) {
+		pal_log_err("setup_fdt fail, ret: 0x%x!\n", ret);
+		ret = -1;
+	}
+
+	/* load odmdtbo and overlay */
+	ret = dtb_overlay(g_fdt, DTB_MAX_SIZE, (uint64_t)recovery_dtbo_offset);
+	if (ret == TRUE) {
+		if (!strcmp(part_name, "recovery")) {
+			set_recovery_dtbo_loaded();
+			pal_log_err("dtb_overlay for recovery done !\n");
+		}
+	}
+	/* command line buffer init */
+	bootargs_init(g_fdt);
+
+	return ret;
+}
+#else /* LK_MAIN_DTB_BUILT_IN */
+static int32_t load_dtbo_from_recoveryimg(void **dtbo_ptr, uint32_t *dtbo_size)
+{
+	int ret = 0;
+	ret = load_vfy_boot(BOOTIMG_TYPE_RECOVERY, 0);
+	if (ret == 0) {
+		*dtbo_ptr = (void *)get_dtbo_load_addr();
+		*dtbo_size = get_dtbo_img_size();
+		set_recovery_img_loaded();
+	}
+	return ret;
+}
+#define DT_TBL_HDR_SIZE		(sizeof(struct dt_table_header))
+int32_t load_dtbo_buffer(void **dtbo_ptr, uint32_t *dtbo_size)
+{
+	void *dtbo_buffer = NULL;
+	struct dt_table_header *dt_tbl_hdr_buffer = NULL;
+	size_t pre_read_dt_tbl_hdr_size = DT_TBL_HDR_SIZE;
+	size_t dtbo_total_len = 0;
+	void *dtbo_total_buffer = NULL;
+	void *selected_dtbo_body_ptr;
+	ssize_t	len;
+	int32_t ret = 0;
+	uint32_t dtbo_offset;
+	uint32_t dtbo_entry_idx;
+	uint32_t _dtbo_size;
+	char *dtbo_from_part_name = get_dtbo_part_name();
+
+	dtbo_total_buffer = target_get_scratch_address();
+	if (dtbo_total_buffer == NULL)
+		panic("scratch address is NULL!\n");
+#ifdef MTK_SECURITY_SW_SUPPORT
+	uint32_t sec_ret;
+	uint32_t vfy_time;
+	unsigned int policy_entry_idx = 0;
+	unsigned int img_auth_required = 0;
+	char *img_name = "dtbo";
+
+	policy_entry_idx = get_policy_entry_idx(dtbo_from_part_name);
+	img_auth_required = get_vfy_policy(policy_entry_idx);
+	/* verify cert chain of boot img */
+	if (img_auth_required) {
+		vfy_time = get_timer(0);
+		sec_ret = sec_img_auth_init(dtbo_from_part_name, img_name, 0);
+		if (sec_ret) {
+			ret = -1;
+			goto end;
+		}
+		dprintf(CRITICAL, "[SBC] image %s cert vfy pass(%d ms)\n", img_name, (unsigned int)get_timer(vfy_time));
+#ifdef MTK_SECURITY_ANTI_ROLLBACK
+		sec_ret = sec_rollback_check(1);
+		if (sec_ret) {
+			dprintf(CRITICAL, "[SBC] image %s ver check fail...(0x%x)\n", img_name, sec_ret);
+			ret = -1;
+			goto end;
+		}
+#endif
+	}
+#endif
+
+	dt_tbl_hdr_buffer = (struct dt_table_header *)malloc(pre_read_dt_tbl_hdr_size);
+	if (dt_tbl_hdr_buffer == NULL) {
+		ret = -ENOMEM;
+		goto end;
+	}
+	/* init dt_tbl_hdr_buffer */
+	memset(dt_tbl_hdr_buffer, 0x0, pre_read_dt_tbl_hdr_size);
+	len = partition_read(dtbo_from_part_name, (off_t)0, (uint8_t *)dt_tbl_hdr_buffer, pre_read_dt_tbl_hdr_size);
+	if (len < 0) {
+		ret = len;
+		goto end;
+	}
+	if (fdt32_to_cpu(dt_tbl_hdr_buffer->magic) != DT_TABLE_MAGIC) {
+		pal_log_err("[%s]dt_table_header magic is not correct:0x%x\n",
+			__func__, fdt32_to_cpu(dt_tbl_hdr_buffer->magic));
+		ret = -EINVAL;
+		goto end;
+	}
+	dtbo_total_len = fdt32_to_cpu(dt_tbl_hdr_buffer->total_size);
+	dprintf(CRITICAL, "dtbo_total_len: 0x%x\n", dtbo_total_len);
+	if (dtbo_total_len > SCRATCH_SIZE) {
+		ret = -1;
+		goto end;
+	}
+	len = partition_read(dtbo_from_part_name, (off_t)0, (uint8_t *)dtbo_total_buffer, dtbo_total_len);
+	if (len < 0) {
+		ret = len;
+		goto end;
+	}
+#ifdef MTK_SECURITY_SW_SUPPORT
+	if (img_auth_required) {
+		vfy_time = get_timer(0);
+		sec_ret = sec_img_auth((uint8_t *)(dtbo_total_buffer + pre_read_dt_tbl_hdr_size), (len - pre_read_dt_tbl_hdr_size));
+		if (sec_ret) {
+			dprintf(CRITICAL, "[SBC] %s vfy fail(%d ms)\n", img_name, (unsigned int)get_timer(vfy_time));
+			ret = -2;
+			goto end;
+		}
+		dprintf(CRITICAL, "[SBC] %s vfy pass(%d ms)\n", img_name, (unsigned int)get_timer(vfy_time));
+	}
+#endif
+
+	/* select dtbo via HW index */
+	ret = parse_dtbo_tbl((struct dt_table_header *)dtbo_total_buffer, (uint32_t)get_odm_mdtbo_index(),
+					&dtbo_entry_idx,
+					(uint32_t *)&_dtbo_size, (uint32_t *)&dtbo_offset);
+	if(ret < 0) {
+		goto end;
+	}
+	if (_dtbo_size > DTB_MAX_SIZE) {
+		ret = -EPERM;
+		goto end;
+	}
+	*dtbo_size = _dtbo_size;
+
+	dtbo_buffer = malloc(_dtbo_size);
+	if (dtbo_buffer == NULL){
+		ret = -ENOMEM;
+		goto end;
+	}
+	dprintf(CRITICAL, "dtbo_offset: 0x%x\n", dtbo_offset);
+	selected_dtbo_body_ptr = dtbo_total_buffer + dtbo_offset;
+	memcpy(dtbo_buffer, selected_dtbo_body_ptr, _dtbo_size);
+	*dtbo_ptr = dtbo_buffer;
+end:
+	/* clear dtbo working buffer */
+	if (dtbo_total_len <= SCRATCH_SIZE)
+		memset(dtbo_total_buffer, 0x0, dtbo_total_len);
+	if (dt_tbl_hdr_buffer)
+		free(dt_tbl_hdr_buffer);
+	/* fail case */
+	if (ret != 0) {
+		dprintf(CRITICAL,"load_dtbo_buffer fail!\n");
+		if (dtbo_buffer)
+			free(dtbo_buffer);
+		*dtbo_ptr = NULL;
+		/* if dtbo load fail, try to load dtbo from recovery image */
+		ret = load_dtbo_from_recoveryimg(dtbo_ptr, dtbo_size);
+		if (ret != 0)
+			dprintf(CRITICAL,"load_dtbo_from_recoveryimg fail!\n");
+	}
+	return ret;
+}
+
+int32_t prepare_kernel_dtb(void)
+{
+	int ret_overlay;
+	uint32_t ret = 0;
+	void *overlayed_dtb = NULL;
+	void *dtbo = NULL;
+	void *main_dtb = NULL;
+	uint32_t dtbo_size = get_dtbo_img_size();
+	uint32_t main_dtb_size = get_main_dtb_size();
+	uint32_t overlayed_dtb_size = 0;
+
+	/*
+	 * dtbo address may not native pointer alignment,
+	 * which will cause unalignment fault.
+	 */
+	if (!IS_ALIGNED(get_dtbo_load_addr(), sizeof(void *))) {
+		dtbo = malloc(dtbo_size);
+		if (dtbo == NULL) {
+			pal_log_err("Fail to malloc %s dtbo\n", __func__);
+			ret = -1;
+			goto end;
+		}
+		if ((void *)get_dtbo_load_addr() == NULL) {
+			ret = -1;
+			goto end;
+		}
+		memcpy(dtbo, (void *)get_dtbo_load_addr(), dtbo_size);
+	}
+	/*
+	 * dtb address may not native pointer alignment,
+	 * which will cause unalignment fault.
+	 */
+	if (!IS_ALIGNED(get_main_dtb_load_addr(), sizeof(void *))) {
+		main_dtb = malloc(main_dtb_size);
+		if (main_dtb == NULL) {
+			pal_log_err("Fail to malloc %s main_dtb\n", __func__);
+			ret = -1;
+			goto end;
+		}
+		if ((void *)get_main_dtb_load_addr() == NULL) {
+			ret = -1;
+			goto end;
+		}
+		memcpy(main_dtb, (void *)get_main_dtb_load_addr(), main_dtb_size);
+	}
+
+	/* overlay dtbo with main dtb */
+	ret_overlay = dtb_overlay(main_dtb ? main_dtb : (void *)get_main_dtb_load_addr(),
+				main_dtb_size,
+				dtbo ? dtbo : (void *)get_dtbo_load_addr(),
+				dtbo_size,
+				&overlayed_dtb, DTB_MAX_SIZE);
+	if (ret_overlay == 0) {
+		if (overlayed_dtb != NULL) {
+			overlayed_dtb_size = fdt_totalsize(overlayed_dtb);
+			if (overlayed_dtb_size > DTB_MAX_SIZE) {
+				pal_log_err("fdt_totalsize(overlayed_dtb):%u is too large!\n", overlayed_dtb_size);
+				ret = -1;
+				goto end;
+			}
+			memcpy(get_kernel_fdt(), overlayed_dtb, overlayed_dtb_size);
+			/* enlarge kernel's fdt for further property setting */
+			fdt_set_totalsize(get_kernel_fdt(), DTB_MAX_SIZE);
+		} else {
+			ret = -1;
+			pal_log_err("overlayed_dtb is NULL");
+		}
+	} else {
+		pal_log_err("boot image dtb_overlay fail");
+		ret = -2;
+	}
+end:
+	if (dtbo)
+		free(dtbo);
+	if (main_dtb)
+		free(main_dtb);
+	if (overlayed_dtb)
+		free(overlayed_dtb);
+	if (ret == 0) {
+		if (dtb_dconfig_overlay(get_kernel_fdt()) == FALSE)
+			pal_log_err("dconfig DT overlay failed, system may not bootable!\n");
+	}
+	return ret;
+}
+
+
+int32_t dtb_overlay(void *main_dtb_addr, uint32_t main_dtb_size,
+					void *dtbo_addr, uint32_t dtbo_size,
+					void **merged_dtb, uint32_t merged_max_size)
+{
+	int ret;
+	struct fdt_header *blob;
+	struct fdt_header *merged_fdt;
+
+	if (!main_dtb_addr ||
+		!main_dtb_size ||
+		!dtbo_addr ||
+		!dtbo_size ||
+		!merged_dtb) {
+		pal_log_err("[%s] input parameter is invalid!\n",
+			__func__);
+		return -EINVAL;
+	}
+	if (merged_max_size < (main_dtb_size + dtbo_size)) {
+		pal_log_err("merged_max_size:%u, main_dtb_size + dtbo_size:%u\n",
+			merged_max_size, main_dtb_size + dtbo_size);
+		return -EINVAL;
+	}
+
+	ret = fdt_open_into(main_dtb_addr, main_dtb_addr, main_dtb_size);
+	if (ret < 0) {
+		pal_log_err("fdt_open_into failed \n");
+		return ret;
+	}
+	blob = ufdt_install_blob(main_dtb_addr, main_dtb_size);
+	if (blob == NULL) {
+		pal_log_err("ufdt_install_blob() failed!\n");
+		return -1;
+	}
+	merged_fdt = ufdt_apply_overlay(blob, main_dtb_size, dtbo_addr, dtbo_size);
+	if (merged_fdt == NULL) {
+		pal_log_err("ufdt_apply_overlay() failed!\n");
+		return -1;
+	}
+	/*
+	  * Compact the merged device tree so that the size of the device tree can
+	  * be known.
+	  */
+	ret = fdt_pack((void *)merged_fdt);
+	if (ret < 0) {
+		pal_log_err("fdt_pack(merged_fdt) failed !\n");
+		if (merged_fdt)
+			free(merged_fdt);
+		return -1;
+	}
+	*merged_dtb = (void *)merged_fdt;
+	return ret;
+}
+#endif
+
+/**************************************************************************************
+* Main device tree loading function, considering loading accordingly from different boot mode
+***************************************************************************************/
+void load_device_tree(void)
+{
+#ifndef LK_MAIN_DTB_BUILT_IN
+	PROFILING_START("early load dtb");
+
+	char *part_name = "boot";
+
+	/* If RECOVERY_AS_BOOT is enabled, there is no recovery partition.  */
+#if !defined(NO_BOOT_MODE_SEL) && !defined(RECOVERY_AS_BOOT)
+	if (Check_RTC_Recovery_Mode() || recovery_check_command_trigger())
+		part_name = "recovery";
+	else
+		part_name = "boot";
+#endif
+
+#if defined(CFG_DTB_EARLY_LOADER_SUPPORT)
+	if (bldr_load_dtb(part_name) < 0)
+		dprintf(CRITICAL, "Error: %s failed\n", __func__);
+#endif
+
+	PROFILING_END();
+#else /* LK_MAIN_DTB_BUILT_IN */
+	lk_dtb_init();
+#endif
+}
+
+int32_t parse_dtbo_tbl(struct dt_table_header *dt_tbl_hdr_buffer,
+		uint32_t hw_board_idx, uint32_t *dtbo_entry_idx_out,
+		uint32_t *dtbo_size, uint32_t *dtbo_offset)
+{
+	struct dt_table_entry *dt_entry_head;
+	struct dt_table_entry *dt_entry_selected;
+	uint32_t dt_entry_cnt;
+	uint32_t dtbo_entry_idx;
+
+	assert(dt_tbl_hdr_buffer);
+	assert(dtbo_entry_idx_out);
+	assert(dtbo_size);
+	assert(dtbo_offset);
+	/* sanity check */
+	if (fdt32_to_cpu(dt_tbl_hdr_buffer->magic) != DT_TABLE_MAGIC) {
+		pal_log_err("[%s]dt_table_header magic is not correct:0x%x\n",
+			__func__, fdt_magic(dt_tbl_hdr_buffer));
+		return -EINVAL;
+	}
+	dt_entry_cnt = fdt32_to_cpu(dt_tbl_hdr_buffer->dt_entry_count);
+	if (dt_entry_cnt > DTBO_ENTRY_CNT_MAX) {
+		pal_log_err("dt_entry_cnt is out of bound: %u, max:%u\n", dt_entry_cnt, DTBO_ENTRY_CNT_MAX);
+		return -EINVAL;
+	}
+	dt_entry_head = (struct dt_table_entry *)(dt_tbl_hdr_buffer + 1);
+	/*
+	 * traverse dt_table_entry list, compare
+	 * dt_table_entry->id with hw_board_idx
+	 */
+	for(dtbo_entry_idx = 0; dtbo_entry_idx < dt_entry_cnt ; dtbo_entry_idx++) {
+		if (hw_board_idx == fdt32_to_cpu((dt_entry_head + dtbo_entry_idx)->id)) {
+			break;
+		}
+	}
+	/* traverse end */
+
+	if (dtbo_entry_idx >= dt_entry_cnt) {
+		dprintf(CRITICAL, "Error: dtbo_entry_idx %d >= num_of_dtbo %d.\n",
+			dtbo_entry_idx, dt_entry_cnt);
+		dprintf(CRITICAL, "Set dtbo_entry_idx to 0 for error handling!\n");
+		dtbo_entry_idx = 0;
+	}
+	set_dtbo_index(dtbo_entry_idx);
+	*dtbo_entry_idx_out = dtbo_entry_idx;
+	dt_entry_selected = dt_entry_head + dtbo_entry_idx;
+	*dtbo_size = fdt32_to_cpu(dt_entry_selected->dt_size);
+	*dtbo_offset = fdt32_to_cpu(dt_entry_selected->dt_offset);
+	return 0;
+}

+ 70 - 0
app/mt_boot/fdt_op.h

@@ -0,0 +1,70 @@
+/* Copyright Statement:
+*
+* This software/firmware and related documentation ("MediaTek Software") are
+* protected under relevant copyright laws. The information contained herein
+* is confidential and proprietary to MediaTek Inc. and/or its licensors.
+* Without the prior written permission of MediaTek inc. and/or its licensors,
+* any reproduction, modification, use or disclosure of MediaTek Software,
+* and information contained herein, in whole or in part, shall be strictly prohibited.
+*/
+/* MediaTek Inc. (C) 2018. All rights reserved.
+*
+* BY OPENING THIS FILE, RECEIVER HEREBY UNEQUIVOCALLY ACKNOWLEDGES AND AGREES
+* THAT THE SOFTWARE/FIRMWARE AND ITS DOCUMENTATIONS ("MEDIATEK SOFTWARE")
+* RECEIVED FROM MEDIATEK AND/OR ITS REPRESENTATIVES ARE PROVIDED TO RECEIVER ON
+* AN "AS-IS" BASIS ONLY. MEDIATEK EXPRESSLY DISCLAIMS ANY AND ALL WARRANTIES,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED WARRANTIES OF
+* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE OR NONINFRINGEMENT.
+* NEITHER DOES MEDIATEK PROVIDE ANY WARRANTY WHATSOEVER WITH RESPECT TO THE
+* SOFTWARE OF ANY THIRD PARTY WHICH MAY BE USED BY, INCORPORATED IN, OR
+* SUPPLIED WITH THE MEDIATEK SOFTWARE, AND RECEIVER AGREES TO LOOK ONLY TO SUCH
+* THIRD PARTY FOR ANY WARRANTY CLAIM RELATING THERETO. RECEIVER EXPRESSLY ACKNOWLEDGES
+* THAT IT IS RECEIVER'S SOLE RESPONSIBILITY TO OBTAIN FROM ANY THIRD PARTY ALL PROPER LICENSES
+* CONTAINED IN MEDIATEK SOFTWARE. MEDIATEK SHALL ALSO NOT BE RESPONSIBLE FOR ANY MEDIATEK
+* SOFTWARE RELEASES MADE TO RECEIVER'S SPECIFICATION OR TO CONFORM TO A PARTICULAR
+* STANDARD OR OPEN FORUM. RECEIVER'S SOLE AND EXCLUSIVE REMEDY AND MEDIATEK'S ENTIRE AND
+* CUMULATIVE LIABILITY WITH RESPECT TO THE MEDIATEK SOFTWARE RELEASED HEREUNDER WILL BE,
+* AT MEDIATEK'S OPTION, TO REVISE OR REPLACE THE MEDIATEK SOFTWARE AT ISSUE,
+* OR REFUND ANY SOFTWARE LICENSE FEES OR SERVICE CHARGE PAID BY RECEIVER TO
+* MEDIATEK FOR SUCH MEDIATEK SOFTWARE AT ISSUE.
+*/
+#if !defined (__FDT_OP_H)
+#define __FDT_OP_H
+#include <odm_mdtbo.h>
+
+#define DTBO_PART_NAME_LEN	16
+/*
+ * FIXME: give a reasonable maximum dtbo
+ * entry count for input validation.
+ */
+#define DTBO_ENTRY_CNT_MAX	10000
+
+typedef enum {
+	DTBO_FROM_STANDALONE = 1,
+	DTBO_FROM_RECOVERY
+} DTBO_SRC;
+
+extern DTBO_SRC get_dtbo_src(void);
+extern char *get_dtbo_part_name(void);
+extern bool setup_fdt(void *fdt, int size);
+extern int bldr_load_dtb(char *boot_load_partition);
+extern void load_device_tree(void);
+int32_t load_dtbo_buffer(void **dtbo_ptr, uint32_t *dtbo_size);
+void setup_kernel_fdt(void *fdt);
+void *get_kernel_fdt(void);
+int32_t prepare_kernel_dtb(void);
+#ifdef LK_MAIN_DTB_BUILT_IN
+int32_t dtb_overlay(void *main_dtb_addr, uint32_t main_dtb_size,
+					void *dtbo_addr, uint32_t dtbo_size,
+					void **merged_dtb, uint32_t merged_max_size);
+int32_t parse_dtbo_tbl(struct dt_table_header *dt_tbl_hdr_buffer,
+		uint32_t hw_board_idx, uint32_t *dtbo_entry_idx_out,
+		uint32_t *dtbo_size, uint32_t *dtbo_offset);
+#else
+extern bool dtb_overlay(void *fdt, int size, uint64_t recovery_dtbo_offset);
+#endif
+
+bool dtb_dconfig_overlay(void *target_fdt);
+
+#endif /* __FDT_OP_H */
+

+ 246 - 0
app/mt_boot/iothread.c

@@ -0,0 +1,246 @@
+/* Copyright Statement:
+*
+* This software/firmware and related documentation ("MediaTek Software") are
+* protected under relevant copyright laws. The information contained herein
+* is confidential and proprietary to MediaTek Inc. and/or its licensors.
+* Without the prior written permission of MediaTek inc. and/or its licensors,
+* any reproduction, modification, use or disclosure of MediaTek Software,
+* and information contained herein, in whole or in part, shall be strictly prohibited.
+*/
+/* MediaTek Inc. (C) 2017. All rights reserved.
+*
+* BY OPENING THIS FILE, RECEIVER HEREBY UNEQUIVOCALLY ACKNOWLEDGES AND AGREES
+* THAT THE SOFTWARE/FIRMWARE AND ITS DOCUMENTATIONS ("MEDIATEK SOFTWARE")
+* RECEIVED FROM MEDIATEK AND/OR ITS REPRESENTATIVES ARE PROVIDED TO RECEIVER ON
+* AN "AS-IS" BASIS ONLY. MEDIATEK EXPRESSLY DISCLAIMS ANY AND ALL WARRANTIES,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED WARRANTIES OF
+* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE OR NONINFRINGEMENT.
+* NEITHER DOES MEDIATEK PROVIDE ANY WARRANTY WHATSOEVER WITH RESPECT TO THE
+* SOFTWARE OF ANY THIRD PARTY WHICH MAY BE USED BY, INCORPORATED IN, OR
+* SUPPLIED WITH THE MEDIATEK SOFTWARE, AND RECEIVER AGREES TO LOOK ONLY TO SUCH
+* THIRD PARTY FOR ANY WARRANTY CLAIM RELATING THERETO. RECEIVER EXPRESSLY ACKNOWLEDGES
+* THAT IT IS RECEIVER'S SOLE RESPONSIBILITY TO OBTAIN FROM ANY THIRD PARTY ALL PROPER LICENSES
+* CONTAINED IN MEDIATEK SOFTWARE. MEDIATEK SHALL ALSO NOT BE RESPONSIBLE FOR ANY MEDIATEK
+* SOFTWARE RELEASES MADE TO RECEIVER'S SPECIFICATION OR TO CONFORM TO A PARTICULAR
+* STANDARD OR OPEN FORUM. RECEIVER'S SOLE AND EXCLUSIVE REMEDY AND MEDIATEK'S ENTIRE AND
+* CUMULATIVE LIABILITY WITH RESPECT TO THE MEDIATEK SOFTWARE RELEASED HEREUNDER WILL BE,
+* AT MEDIATEK'S OPTION, TO REVISE OR REPLACE THE MEDIATEK SOFTWARE AT ISSUE,
+* OR REFUND ANY SOFTWARE LICENSE FEES OR SERVICE CHARGE PAID BY RECEIVER TO
+* MEDIATEK FOR SUCH MEDIATEK SOFTWARE AT ISSUE.
+*/
+
+#include <debug.h>
+#include <iothread.h>
+#include <profiling.h>
+#include <spm_common.h>
+#include <lk_load_md_wrapper.h>
+#ifdef MTK_TINYSYS_SCP_SUPPORT
+#include <platform/mt_scp.h>		// for load_scp() and disable_scp_hw()
+#endif  // MTK_TINYSYS_SCP_SUPPORT
+#ifdef MTK_VPU_SUPPORT
+#include <platform/mt_vpu.h>
+#endif
+#ifdef MTK_AUDIODSP_SUPPORT
+#include <platform/mt_adsp.h>
+#endif  // MTK_AUDIODSP_SUPPORT
+
+#ifdef MTK_DPM_SUPPORT
+#include <platform/mt_dpm.h>
+#endif
+/******************************************************************************
+******************************************************************************/
+event_t iothread_start_event;
+event_t iothread_end_event;
+extern BOOTMODE g_boot_mode;
+extern int modem_image_loaded;
+extern ulong get_timer (ulong base);
+/******************************************************************************
+******************************************************************************/
+extern int mcdi_load_mcupm(void);
+/******************************************************************************
+******************************************************************************/
+
+static void do_load_spm(BOOTMODE mode)
+{
+#ifdef SPM_FW_USE_PARTITION
+	PROFILING_START("load spm");
+	load_spm();
+	PROFILING_END();
+#endif
+
+}
+
+static void do_load_dpm(BOOTMODE mode)
+{
+#ifdef MTK_DPM_SUPPORT
+        PROFILING_START("load dpm");
+        load_dpm();
+        PROFILING_END();
+#endif
+}
+
+static void do_load_scp(BOOTMODE mode)
+{
+#ifdef MTK_TINYSYS_SCP_SUPPORT
+	PROFILING_START("load scp");
+	if (mode != RECOVERY_BOOT) {
+		if (load_scp() < 0) {
+			/* if it load scp fail, turn off SCP hw*/
+			disable_scp_hw();
+		}
+	} else {
+		/* turn off scp in recovery mode*/
+		disable_scp_hw();
+	}
+	PROFILING_END();
+#endif
+}
+
+static void do_load_adsp(BOOTMODE mode)
+{
+#ifdef MTK_AUDIODSP_SUPPORT
+	PROFILING_START("load adsp");
+	if (mode != RECOVERY_BOOT) {
+		if (load_adsp() < 0) {
+			/* if it load adsp fail, turn off ADSP hw*/
+			disable_adsp_hw();
+		}
+	} else {
+		/* turn off adsp in recovery mode*/
+		dprintf(CRITICAL,"[adsp] recovery mode, no need to load adsp\n");
+		disable_adsp_hw();
+	}
+	PROFILING_END();
+#endif
+}
+
+static void do_load_mcupm(BOOTMODE mode)
+{
+#ifdef MCUPM_FW_USE_PARTITION
+	PROFILING_START("load mcupm");
+	mcdi_load_mcupm();
+	PROFILING_END();
+#endif
+}
+
+static void do_load_modem(BOOTMODE mode)
+{
+	PROFILING_START("load modem image");
+	/* NOTE: This MUST before setup_mem_property_use_mblock_info() !!! */
+	if (modem_image_loaded) { // no need to load modem for "fastboot contiinue"
+		dprintf(CRITICAL,"[ccci] modem already loaded in fastboot_init. no need load modem here\n");
+	} else if (mode != RECOVERY_BOOT
+#if defined(MTK_KERNEL_POWER_OFF_CHARGING)
+			&& mode != KERNEL_POWER_OFF_CHARGING_BOOT
+			&& mode != LOW_POWER_OFF_CHARGING_BOOT
+#endif
+		) {
+		ccci_load_modem_image();
+	} else {
+		dprintf(CRITICAL,"[ccci] recovery mode, no need load modem\n");
+	}
+#if !defined(NO_MD_POWER_DOWN)
+	/* just for 93: SBC on 93, need call power off after load modem image */
+	extern void md_power_down(void)__attribute__((weak));
+	if (md_power_down) {
+		md_power_down();
+	} else {
+		dprintf(CRITICAL,"[ccci-off] later power down not needed or not ready!\n");
+	}
+#endif
+	extern int md_power_control(BOOTMODE mode)__attribute__((weak));
+	if (md_power_control) {
+		md_power_control(mode);
+	} else {
+		dprintf(CRITICAL,"[ccci-off] later power down not needed or not ready!\n");
+	}
+	PROFILING_END();
+}
+
+static void do_load_vpu(BOOTMODE mode)
+{
+#ifdef MTK_VPU_SUPPORT
+#ifndef MTK_VPU_LOAD_IMAGE
+	int ret;
+	PROFILING_START("load vpu");
+	if ((ret = mt_load_vpu()) < 0) {
+		dprintf(CRITICAL, "[LK ERROR] load VPU fail(ret = %d)!!!\n", ret);
+	}
+	PROFILING_END();
+#endif
+#endif
+}
+
+static void do_load_images(BOOTMODE mode)
+{
+	/* Don't load fw which not needed in recovery
+	* This is to ensure recovery can be entered
+	* even borken images are detected by verify boot
+	*/
+	if (RECOVERY_BOOT != mode) {
+		do_load_vpu(mode);
+		do_load_spm(mode);
+		do_load_mcupm(mode);
+	}
+	/* Actially the md img is not loaded in recovery too.
+	* Check inside this API, md power down to be decoupled
+	*/
+	do_load_scp(mode);
+	do_load_modem(mode);
+	do_load_adsp(mode);
+	do_load_dpm(mode);
+}
+
+
+/******************************************************************************
+******************************************************************************/
+#if !defined(ENABLE_IO_THREAD)
+void load_images(BOOTMODE mode)
+{
+	do_load_images(mode);
+}
+
+#else
+
+void load_images(BOOTMODE mode)
+{
+	/* Empty! */
+}
+#endif  // ENABLE_IO_THREAD
+
+
+/******************************************************************************
+******************************************************************************/
+#if defined(ENABLE_IO_THREAD)
+static void load_images_in_iothread(BOOTMODE mode)
+{
+	do_load_images(mode);
+}
+
+#else
+
+static void load_images_in_iothread(BOOTMODE mode)
+{
+	/* Empty! */
+}
+#endif  // ENABLE_IO_THREAD
+
+
+/******************************************************************************
+******************************************************************************/
+int iothread(void *arg)
+{
+	event_init(&iothread_start_event, false, 0);
+	event_init(&iothread_end_event, false, 0);
+	dprintf(INFO, "iothread starts.\n");
+
+	wait_for_bootstrap2();
+
+	load_images_in_iothread(g_boot_mode);
+
+	wake_up_bootstrap2();
+
+	return 0;
+}
+
+

+ 92 - 0
app/mt_boot/iothread.h

@@ -0,0 +1,92 @@
+/* Copyright Statement:
+*
+* This software/firmware and related documentation ("MediaTek Software") are
+* protected under relevant copyright laws. The information contained herein
+* is confidential and proprietary to MediaTek Inc. and/or its licensors.
+* Without the prior written permission of MediaTek inc. and/or its licensors,
+* any reproduction, modification, use or disclosure of MediaTek Software,
+* and information contained herein, in whole or in part, shall be strictly prohibited.
+*/
+/* MediaTek Inc. (C) 2017. All rights reserved.
+*
+* BY OPENING THIS FILE, RECEIVER HEREBY UNEQUIVOCALLY ACKNOWLEDGES AND AGREES
+* THAT THE SOFTWARE/FIRMWARE AND ITS DOCUMENTATIONS ("MEDIATEK SOFTWARE")
+* RECEIVED FROM MEDIATEK AND/OR ITS REPRESENTATIVES ARE PROVIDED TO RECEIVER ON
+* AN "AS-IS" BASIS ONLY. MEDIATEK EXPRESSLY DISCLAIMS ANY AND ALL WARRANTIES,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED WARRANTIES OF
+* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE OR NONINFRINGEMENT.
+* NEITHER DOES MEDIATEK PROVIDE ANY WARRANTY WHATSOEVER WITH RESPECT TO THE
+* SOFTWARE OF ANY THIRD PARTY WHICH MAY BE USED BY, INCORPORATED IN, OR
+* SUPPLIED WITH THE MEDIATEK SOFTWARE, AND RECEIVER AGREES TO LOOK ONLY TO SUCH
+* THIRD PARTY FOR ANY WARRANTY CLAIM RELATING THERETO. RECEIVER EXPRESSLY ACKNOWLEDGES
+* THAT IT IS RECEIVER'S SOLE RESPONSIBILITY TO OBTAIN FROM ANY THIRD PARTY ALL PROPER LICENSES
+* CONTAINED IN MEDIATEK SOFTWARE. MEDIATEK SHALL ALSO NOT BE RESPONSIBLE FOR ANY MEDIATEK
+* SOFTWARE RELEASES MADE TO RECEIVER'S SPECIFICATION OR TO CONFORM TO A PARTICULAR
+* STANDARD OR OPEN FORUM. RECEIVER'S SOLE AND EXCLUSIVE REMEDY AND MEDIATEK'S ENTIRE AND
+* CUMULATIVE LIABILITY WITH RESPECT TO THE MEDIATEK SOFTWARE RELEASED HEREUNDER WILL BE,
+* AT MEDIATEK'S OPTION, TO REVISE OR REPLACE THE MEDIATEK SOFTWARE AT ISSUE,
+* OR REFUND ANY SOFTWARE LICENSE FEES OR SERVICE CHARGE PAID BY RECEIVER TO
+* MEDIATEK FOR SUCH MEDIATEK SOFTWARE AT ISSUE.
+*/
+
+#include <kernel/event.h>		// for event_t
+#include <platform/boot_mode.h>		// for BOOTMODE
+
+
+/******************************************************************************
+******************************************************************************/
+#define IO_THREAD_PRIORITY (DEFAULT_PRIORITY + 1)
+
+
+/******************************************************************************
+******************************************************************************/
+extern event_t iothread_start_event;
+extern event_t iothread_end_event;
+
+
+/******************************************************************************
+******************************************************************************/
+#define wake_up_iothread()                                                    \
+	do {                                                                  \
+		dprintf(INFO, "Wake up iothread.\n");                         \
+		event_signal(&iothread_start_event, false);                   \
+	} while (0)
+
+
+/******************************************************************************
+******************************************************************************/
+#define wait_for_iothread()                                                   \
+	do {                                                                  \
+		dprintf(INFO, "Wait for iothread...\n");                      \
+		event_wait(&iothread_end_event);                              \
+		event_unsignal(&iothread_end_event);                          \
+		dprintf(INFO, "Met iothread.\n");                             \
+	} while (0)
+
+
+/******************************************************************************
+******************************************************************************/
+#define wake_up_bootstrap2()                                                  \
+	do {                                                                  \
+		dprintf(INFO, "Wake up bootstrap2.\n");                       \
+		event_signal(&iothread_end_event, true);                      \
+	} while (0)
+
+
+/******************************************************************************
+******************************************************************************/
+#define wait_for_bootstrap2()                                                 \
+	do {                                                                  \
+		dprintf(INFO, "Wait for bootstrap2...\n");                    \
+		event_wait(&iothread_start_event);                            \
+		event_unsignal(&iothread_start_event);                        \
+		dprintf(INFO, "Met bootstrap2.\n");                           \
+	} while (0)
+
+
+/******************************************************************************
+******************************************************************************/
+void load_images(BOOTMODE mode);
+int iothread(void *arg);
+
+

+ 2046 - 0
app/mt_boot/mt_boot.c

@@ -0,0 +1,2046 @@
+/* Copyright Statement:
+*
+* This software/firmware and related documentation ("MediaTek Software") are
+* protected under relevant copyright laws. The information contained herein
+* is confidential and proprietary to MediaTek Inc. and/or its licensors.
+* Without the prior written permission of MediaTek inc. and/or its licensors,
+* any reproduction, modification, use or disclosure of MediaTek Software,
+* and information contained herein, in whole or in part, shall be strictly prohibited.
+*/
+/* MediaTek Inc. (C) 2015. All rights reserved.
+*
+* BY OPENING THIS FILE, RECEIVER HEREBY UNEQUIVOCALLY ACKNOWLEDGES AND AGREES
+* THAT THE SOFTWARE/FIRMWARE AND ITS DOCUMENTATIONS ("MEDIATEK SOFTWARE")
+* RECEIVED FROM MEDIATEK AND/OR ITS REPRESENTATIVES ARE PROVIDED TO RECEIVER ON
+* AN "AS-IS" BASIS ONLY. MEDIATEK EXPRESSLY DISCLAIMS ANY AND ALL WARRANTIES,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED WARRANTIES OF
+* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE OR NONINFRINGEMENT.
+* NEITHER DOES MEDIATEK PROVIDE ANY WARRANTY WHATSOEVER WITH RESPECT TO THE
+* SOFTWARE OF ANY THIRD PARTY WHICH MAY BE USED BY, INCORPORATED IN, OR
+* SUPPLIED WITH THE MEDIATEK SOFTWARE, AND RECEIVER AGREES TO LOOK ONLY TO SUCH
+* THIRD PARTY FOR ANY WARRANTY CLAIM RELATING THERETO. RECEIVER EXPRESSLY ACKNOWLEDGES
+* THAT IT IS RECEIVER'S SOLE RESPONSIBILITY TO OBTAIN FROM ANY THIRD PARTY ALL PROPER LICENSES
+* CONTAINED IN MEDIATEK SOFTWARE. MEDIATEK SHALL ALSO NOT BE RESPONSIBLE FOR ANY MEDIATEK
+* SOFTWARE RELEASES MADE TO RECEIVER'S SPECIFICATION OR TO CONFORM TO A PARTICULAR
+* STANDARD OR OPEN FORUM. RECEIVER'S SOLE AND EXCLUSIVE REMEDY AND MEDIATEK'S ENTIRE AND
+* CUMULATIVE LIABILITY WITH RESPECT TO THE MEDIATEK SOFTWARE RELEASED HEREUNDER WILL BE,
+* AT MEDIATEK'S OPTION, TO REVISE OR REPLACE THE MEDIATEK SOFTWARE AT ISSUE,
+* OR REFUND ANY SOFTWARE LICENSE FEES OR SERVICE CHARGE PAID BY RECEIVER TO
+* MEDIATEK FOR SUCH MEDIATEK SOFTWARE AT ISSUE.
+*/
+
+#include <atags.h>              // for target_atag_masp_data()
+#include <app.h>
+#include <debug.h>
+#include <arch.h>
+#include <arch/arm.h>
+#include <arch/arm/mmu.h>
+#include <dev/udc.h>
+#include <reg.h>
+#include <string.h>
+#include <stdlib.h>
+#include <kernel/thread.h>
+#include <arch/ops.h>
+#include <ctype.h>
+#include <target.h>
+#include <platform.h>
+#include <platform/mt_reg_base.h>
+#include <platform/boot_mode.h>
+#include <load_vfy_boot.h>
+#include <boot_opt.h>
+#include <bootimg.h>
+#include <boot_info.h>
+#ifdef MTK_GPT_SCHEME_SUPPORT
+#include <platform/partition.h>
+#else
+#include <mt_partition.h>
+#endif
+#include <platform/mt_disp_drv.h>
+#ifdef MTK_PARTITION_COMMON
+#include <env.h>
+#else
+#include <platform/env.h>
+#endif
+#include <target/cust_usb.h>
+#include <platform/mt_gpt.h>
+#if defined(MTK_SECURITY_SW_SUPPORT)
+#include "oemkey.h"
+#endif
+#include <video.h>              // for video_printf()
+#ifdef CFG_MTK_WDT_COMMON
+#include <mtk_wdt.h>
+#else
+#include <platform/mtk_wdt.h>   // for mtk_wdt_disable()
+#endif
+#include <mt_boot.h>
+#include <libfdt.h>
+#include <ufdt_overlay.h>       // for ufdt_install_blob(), ufdt_apply_overlay()
+#include <mt_rtc.h>             // for Check_RTC_Recovery_Mode()
+#include <part_interface.h>     // for partition_read()
+#include <dev/mrdump.h>         // for mrdump_init()
+#include <iothread.h>
+#include <RoT.h>
+#include <odm_mdtbo.h>          // for load_overlay_dtbo()
+
+#include <profiling.h>
+#include <rnd.h>
+#include <verified_boot_common.h>
+#include <platform/ram_console.h>
+
+#include <lk_load_md_wrapper.h> // for ccci load modem image relate
+#include <pal_assert.h>
+#include <pal_typedefs.h>
+#include <pal_log.h>
+#include <memory_layout.h>
+#ifdef MTK_RECOVERY_RAMDISK_SPLIT
+#include <load_vfy_ramdisk.h>
+#endif
+#include <bootargs.h>
+#include <platform/mtk_wdt.h>
+#include <error.h>
+#include <chip_id.h>
+#include <img_workbuf.h>
+
+#ifndef LK_RAMDISK_MAX_SIZE
+#define LK_RAMDISK_MAX_SIZE		(16*1024*1024)
+#endif /* LK_RAMDISK_MAX_SIZE */
+
+#define TMPBUF_SIZE        200
+//#define MTK_DEBUG_SHELL
+
+
+#ifdef MBLOCK_LIB_SUPPORT
+#include <mblock.h>
+#endif
+
+#ifdef MTK_AB_OTA_UPDATER
+#include "bootctrl.h"
+#endif
+
+#include <dev/uart.h>
+#include <sec_hrid.h>
+#include <sec_devinfo.h>
+
+#include <log_store_lk.h>
+#include <lib/heap.h>
+
+extern u32 current_lk_buf_addr_get(void) __attribute__((weak));
+extern u32 current_buf_addr_get(void) __attribute__((weak));
+extern u32 current_buf_pl_lk_log_size_get(void) __attribute__((weak));
+enum {
+	RUNTIME_LOG_DEACTIVATED = 0,
+	RUNTIME_LOG_ACTIVATED
+};
+u8 g_lk_final_log = RUNTIME_LOG_ACTIVATED;
+
+// FIXME!!! The following function declaration should not exist, and appropriate
+//          header files instead should be included.
+void write_protect_flow(void) __attribute__((weak));
+int mboot_recovery_load_raw_part(char *part_name, unsigned long *addr,
+				 unsigned int size);
+
+extern int kernel_charging_boot(void) __attribute__((weak));
+extern int pmic_detect_powerkey(void);
+extern void mt65xx_backlight_off(void);
+
+extern void jumparch64_smc(u32 addr, u32 arg1, u32 arg2, u32 arg3);
+
+extern u32 memory_size(void);
+extern unsigned *target_atag_devinfo_data(unsigned *ptr);
+extern unsigned *target_atag_videolfb(unsigned *ptr, size_t buf_size);
+extern unsigned *target_atag_mdinfo(unsigned *ptr);
+extern unsigned *target_atag_ptp(unsigned *ptr);
+extern void platform_uninit(void);
+extern void custom_port_in_kernel(BOOTMODE boot_mode, char *command);
+extern const char *mt_disp_get_lcm_id(void);
+extern unsigned int DISP_GetVRamSize(void);
+extern int mt_disp_is_lcm_connected(void);
+extern int disp_lcm_fill_lcm_dts_phandle(void* fdt, int idx) __attribute__((weak));
+extern int disp_lcm_get_dts_panel_index(void)  __attribute__((weak));
+extern int fastboot_init(void *base, unsigned size);
+extern int sec_boot_check(int try_lock);
+extern int seclib_set_oemkey(u8 *key, u32 key_size);
+extern BI_DRAM bi_dram[MAX_NR_BANK];
+#ifdef DEVICE_TREE_SUPPORT
+#include <libfdt.h>
+extern unsigned int *device_tree, device_tree_size;
+#endif
+extern unsigned int g_boot_state;
+extern int platform_skip_hibernation(void) __attribute__((weak));
+extern int is_meta_log_disable(void)__attribute__((weak));
+
+extern int g_is_64bit_kernel;
+u32 g_64bit_dtb_size = 0;
+
+#if defined(MBLOCK_LIB_SUPPORT) && defined(MTK_3LEVEL_PAGETABLE)
+#define ALLOCATE_FROM_MBLOCK
+#endif
+
+#ifdef ALLOCATE_FROM_MBLOCK
+/* Occupy dtb/kernel/randisk from mblock */
+u32 dtb_kernel_addr_mb = 0;
+u32 kernel_addr_mb = 0;
+u32 ramdisk_addr_mb = 0;
+u32 kernel_sz_mb = 0;
+u32 ramdisk_sz_mb = 0;
+u32 lk_addr_mb = 0;
+u32 scratch_addr_mb = 0;
+static u32 kernel_align = PAGE_SIZE;
+#endif
+
+#if defined(MTK_SECURITY_SW_SUPPORT)
+u8 g_oemkey[OEM_PUBK_SZ] = {OEM_PUBK};
+#endif
+
+/* battery driver related */
+signed int fg_swocv_v;
+signed int fg_swocv_i;
+int shutdown_time;
+int boot_voltage;
+int two_sec_reboot;
+
+#ifdef MTK_AB_OTA_UPDATER
+const char *p_AB_suffix;
+static uint8_t AB_retry_count;
+#endif /* MTK_AB_OTA_UPDATER */
+
+/* Please define SN_BUF_LEN in cust_usb.h */
+#ifndef SN_BUF_LEN
+#define SN_BUF_LEN  19  /* fastboot use 13 bytes as default, max is 19 */
+#endif
+
+#define FDT_BUFF_SIZE		(2048) //must align with CMDLINE_LEN
+#define FDT_CHECKER_SIZE	(8)
+#define FDT_SPARE_SIZE		(FDT_BUFF_SIZE + FDT_CHECKER_SIZE)
+#define FDT_BUFF_END	 	"BUFFEND"
+
+#define DEFAULT_SERIAL_NUM "0123456789ABCDEF"
+
+#define KERNEL_64BITS 1
+#define KERNEL_32BITS 0
+
+#define VIDEOLFB_PRE_HEADER_LENGTH  (5)
+
+/* define meta init.rc path */
+#if defined (MTK_RC_TO_VENDOR)
+#define META_INIT_RC        "/vendor/etc/init/hw/meta_init.rc"
+#define FACTORY_INIT_RC     "/vendor/etc/init/hw/factory_init.rc"
+#else
+#define META_INIT_RC        "/meta_init.rc"
+#define FACTORY_INIT_RC     "/factory_init.rc"
+#endif
+
+/*
+ * Support read barcode from /dev/pro_info to be serial number.
+ * Then pass the serial number from cmdline to kernel.
+ */
+/* The following option should be defined in project make file. */
+#define SERIAL_NUM_FROM_BARCODE
+
+#if defined(CONFIG_MTK_USB_UNIQUE_SERIAL) || (defined(MTK_SECURITY_SW_SUPPORT) && defined(MTK_SEC_FASTBOOT_UNLOCK_SUPPORT))
+#define SERIALNO_LEN    38  /* from preloader */
+char sn_buf[SN_BUF_LEN + 1] = ""; /* will read from EFUSE_CTR_BASE */
+#else
+#define SERIALNO_LEN    38
+char sn_buf[SN_BUF_LEN + 1] = FASTBOOT_DEVNAME;
+#endif
+
+static struct udc_device surf_udc_device = {
+	.vendor_id  = USB_VENDORID,
+	.product_id = USB_PRODUCTID,
+	.version_id = USB_VERSIONID,
+	.manufacturer   = USB_MANUFACTURER,
+	.product    = USB_PRODUCT_NAME,
+};
+
+typedef enum BUILD_TYPE {
+	BUILD_TYPE_USER         = 0,
+	BUILD_TYPE_USERDEBUG    = 1,
+	BUILD_TYPE_ENG          = 2
+} BUILD_TYPE_T;
+
+/****************************************************************************
+* Note that userdebug build defines both USERDEBUG_BUILD and USER_BUILD for
+* backward compatibility for now.  Therefore, it is important to check
+* USERDEBUG_BUILD before checking USER_BUILD.
+****************************************************************************/
+#ifdef USERDEBUG_BUILD
+static BUILD_TYPE_T eBuildType = BUILD_TYPE_USERDEBUG;
+#elif defined(USER_BUILD)
+static BUILD_TYPE_T eBuildType = BUILD_TYPE_USER;
+#elif defined(ENG_BUILD)
+static BUILD_TYPE_T eBuildType = BUILD_TYPE_ENG;
+#else
+static BUILD_TYPE_T eBuildType = BUILD_TYPE_USER;
+#endif
+
+void msg_header_error(char *img_name)
+{
+	pal_log_err("[MBOOT] Load '%s' partition Error\n", img_name);
+	pal_log_err(
+		"\n*******************************************************\n");
+	pal_log_err("ERROR.ERROR.ERROR.ERROR.ERROR.ERROR.ERROR.ERROR.ERROR\n");
+	pal_log_err("*******************************************************\n");
+	pal_log_err("> If you use NAND boot\n");
+	pal_log_err("> (1) %s is wrong !!!! \n", img_name);
+	pal_log_err(
+		"> (2) please make sure the image you've downloaded is correct\n");
+	pal_log_err("\n> If you use MSDC boot\n");
+	pal_log_err("> (1) %s is not founded in SD card !!!! \n", img_name);
+	pal_log_err("> (2) please make sure the image is put in SD card\n");
+	pal_log_err("*******************************************************\n");
+	pal_log_err("ERROR.ERROR.ERROR.ERROR.ERROR.ERROR.ERROR.ERROR.ERROR\n");
+	pal_log_err("*******************************************************\n");
+	mtk_wdt_disable();
+	mdelay(8000);
+	mtk_arch_reset(1);
+}
+
+void msg_img_error(char *img_name)
+{
+	pal_log_err("[MBOOT] Load '%s' partition Error\n", img_name);
+	pal_log_err(
+		"\n*******************************************************\n");
+	pal_log_err("ERROR.ERROR.ERROR.ERROR.ERROR.ERROR.ERROR.ERROR.ERROR\n");
+	pal_log_err("*******************************************************\n");
+	pal_log_err("> Please check kernel and rootfs in %s are both correct.\n",
+		img_name);
+	pal_log_err("*******************************************************\n");
+	pal_log_err("ERROR.ERROR.ERROR.ERROR.ERROR.ERROR.ERROR.ERROR.ERROR\n");
+	pal_log_err("*******************************************************\n");
+	mtk_wdt_disable();
+	mdelay(8000);
+	mtk_arch_reset(1);
+}
+
+//*********
+//* Notice : it's kernel start addr (and not include any debug header)
+extern unsigned int g_kmem_off;
+
+//*********
+//* Notice : it's rootfs start addr (and not include any debug header)
+extern int g_nr_bank;
+extern unsigned int boot_time;
+extern BOOT_ARGUMENT *g_boot_arg;
+extern bool g_boot_reason_change __attribute__((weak));
+extern int has_set_p2u;
+extern unsigned int g_fb_base;
+extern unsigned int g_fb_size;
+unsigned int logo_lk_t = 0;
+bool boot_ftrace = false;
+
+static int boot_time_via_dt(void *fdt, unsigned int *lk_boot_time)
+{
+	int offset, nodeoffset, ret = 0;
+	unsigned int pl_t = 0, i;
+	const char *boot_names[] = {"pl_t","lk_t","lk_logo_t"};
+	const char *main_boot_name;
+
+	offset = fdt_path_offset(fdt, "/");
+	if (offset < 0) {
+		dprintf(CRITICAL,"Warning: can't search root node in device tree\n");
+	}
+
+	nodeoffset = fdt_add_subnode(fdt, offset, "bootprof");
+	if (nodeoffset < 0) {
+		dprintf(CRITICAL,"Warning: can't add bootprof node in device tree\n");
+		return -1;
+	} else {
+		pl_t = g_boot_arg->boot_time;
+		*lk_boot_time = (unsigned int)get_timer(boot_time);
+		int boot_times[] = {cpu_to_fdt32(pl_t), cpu_to_fdt32(*lk_boot_time),
+			cpu_to_fdt32(logo_lk_t)};
+		for (i = 0; i < sizeof(boot_times)/sizeof(boot_times[0]); i++) {
+			main_boot_name = boot_names[i];
+			ret = fdt_setprop(fdt, nodeoffset, main_boot_name, &boot_times[i],
+				sizeof(unsigned int));
+			if (ret) {
+				dprintf(CRITICAL,"Warning: can't add %s property in device tree\n",
+					main_boot_name);
+				return -1;
+			}
+		}
+	}
+
+	return ret;
+}
+
+void __attribute__((weak)) send_root_of_trust_info(void){}
+
+static void mboot_free_lk_scratch_from_mblock()
+{
+#ifdef ALLOCATE_FROM_MBLOCK
+	/* when mrdump is enabled, kernel should*/
+	/* not use any memory which may be corrupt */
+	/* before lk start dump in case those memory*/
+	/* has important data but be corrupted before dump*/
+	/* Free before stepping into kernel */
+	if (lk_addr_mb != 0) {
+		mblock_create(&g_boot_arg->mblock_info,
+			&g_boot_arg->orig_dram_info,
+			(u64)lk_addr_mb, (u64)MEMSIZE);
+	}
+
+	if (scratch_addr_mb != 0) {
+		mblock_create(&g_boot_arg->mblock_info,
+			&g_boot_arg->orig_dram_info,
+			(u64)scratch_addr_mb, (u64)(SCRATCH_SIZE));
+	}
+#endif
+}
+
+void mboot_allocate_lk_scratch_from_mblock()
+{
+#ifdef ALLOCATE_FROM_MBLOCK
+	/* never allocate mb more than once */
+	if ((lk_addr_mb == MEMBASE)||(scratch_addr_mb == SCRATCH_ADDR))
+		return;
+
+	// Claim the LK MEMBASE from mblock during its life time
+	lk_addr_mb = (u32)mblock_reserve_ext(&g_boot_arg->mblock_info,
+			MEMSIZE, SECTION_SIZE, (MEMBASE + MEMSIZE),
+			0, "lk_addr_mb");
+
+	// Claim the LK SCRATCH from mblock during its life time (including logo)
+	scratch_addr_mb = (u32)mblock_reserve_ext(&g_boot_arg->mblock_info,
+			SCRATCH_SIZE, PAGE_SIZE, (SCRATCH_ADDR + SCRATCH_SIZE),
+			0, "scratch_addr_mb");
+
+	/* Check if the clarmed mb address the same as predefined one */
+	if ((!lk_addr_mb) || (lk_addr_mb != MEMBASE)) {
+		pal_log_err("Warning! MEMBASE (0x%x) is not taken from mb (0x%x)\n", MEMBASE, lk_addr_mb);
+		assert(0);
+	}
+	if ((!scratch_addr_mb) || (scratch_addr_mb != SCRATCH_ADDR)) {
+		pal_log_err("Warning! SCRATCH (0x%x) is not taken from mb (0x%x)\n", SCRATCH_ADDR, scratch_addr_mb);
+		assert(0);
+	}
+#endif
+}
+
+static void mboot_free_bootimg_from_mblock()
+{
+#ifdef ALLOCATE_FROM_MBLOCK
+	/* when mrdump is enabled, kernel should*/
+	/* not use any memory which may be corrupt */
+	/* before lk start dump in case those memory*/
+	/* has important data but be corrupted before dump*/
+	/* Return the bootimg mb before stepping into kernel */
+	if (dtb_kernel_addr_mb != 0) {
+		mblock_create(&g_boot_arg->mblock_info,
+			&g_boot_arg->orig_dram_info,
+			(u64)dtb_kernel_addr_mb, (u64)DTB_MAX_SIZE);
+	}
+
+	if (kernel_addr_mb != 0) {
+		mblock_create(&g_boot_arg->mblock_info,
+			&g_boot_arg->orig_dram_info,
+			(u64)kernel_addr_mb, (u64)kernel_sz_mb);
+	}
+
+	if (ramdisk_addr_mb != 0) {
+		mblock_create(&g_boot_arg->mblock_info,
+			&g_boot_arg->orig_dram_info,
+			(u64)ramdisk_addr_mb, (u64)ramdisk_sz_mb);
+	}
+#endif
+}
+
+
+void mboot_allocate_bootimg_from_mblock(struct bootimg_hdr *p_boot_hdr)
+{
+#ifdef ALLOCATE_FROM_MBLOCK
+
+	int skip_ramdisk_check = 0;
+
+	/* never allocate mb more than once */
+	if ((kernel_addr_mb == p_boot_hdr->kernel_addr)||
+	(ramdisk_addr_mb == p_boot_hdr->ramdisk_addr)||
+	(dtb_kernel_addr_mb == p_boot_hdr->tags_addr))
+		return;
+
+#ifdef LK_KERNEL_64_MAX_SIZE
+	/* use dynamic kernel laoding when
+	 * p_boot_hdr->kernel_addr = KERNEL_MBLOCK_LIMIT - LK_DYNAMIC_KERNEL_64_MAX_SIZE
+	 */
+#ifdef LK_DYNAMIC_KERNEL_64_MAX_SIZE
+	if (p_boot_hdr->kernel_addr == KERNEL_MBLOCK_LIMIT - LK_DYNAMIC_KERNEL_64_MAX_SIZE)
+		kernel_sz_mb = LK_DYNAMIC_KERNEL_64_MAX_SIZE;
+	else
+#endif
+		kernel_sz_mb = LK_KERNEL_64_MAX_SIZE;
+
+	if (g_is_64bit_kernel)
+		kernel_align = 0x80000;
+	else
+		kernel_align = 0x8000;
+#else
+	kernel_sz_mb = 0x03200000;
+#endif
+	ramdisk_sz_mb = ROUNDUP(LK_RAMDISK_MAX_SIZE, PAGE_SIZE);
+	if (ramdisk_sz_mb == 0)
+		skip_ramdisk_check = 1;
+
+	/* To avoid dtb being corrupted, use mblock to claim it now */
+	dtb_kernel_addr_mb = (u32)mblock_reserve_ext(&g_boot_arg->mblock_info,
+		DTB_MAX_SIZE, DTB_MAX_SIZE, (p_boot_hdr->tags_addr+DTB_MAX_SIZE),
+		1, "dtb_kernel_addr_mb");
+
+	kernel_addr_mb = (u32)mblock_reserve_ext(&g_boot_arg->mblock_info,
+		kernel_sz_mb, kernel_align,(p_boot_hdr->kernel_addr+kernel_sz_mb),
+		0, "kernel_addr_mb");
+
+	if (!skip_ramdisk_check) {
+		ramdisk_addr_mb = (u32)mblock_reserve_ext(&g_boot_arg->mblock_info,
+			ramdisk_sz_mb, PAGE_SIZE,(p_boot_hdr->ramdisk_addr+ramdisk_sz_mb),
+			0, "ramdisk_addr_mb");
+	}
+	/* Check if the claimed mb address the same as predefined one
+	 * For Dynamic Kernel Loading
+	 *   return address != NULL
+	 *   predefined address for ASAN project
+	 *     p_boot_hdr->tags_addr = KERNEL_MBLOCK_LIMIT - DTB_MAX_SIZE
+	 *     p_boot_hdr->kernel_addr = KERNEL_MBLOCK_LIMIT - LK_DYNAMIC_KERNEL_64_MAX_SIZE
+	 *     p_boot_hdr->ramdisk_addr = KERNEL_MBLOCK_LIMIT - ROUNDUP(LK_RAMDISK_MAX_SIZE, PAGE_SIZE)
+	 * For Static Kernel Loading
+	 *   return value != predefined address
+	 *   return address != NULL
+	 */
+	if ((!dtb_kernel_addr_mb) || ((dtb_kernel_addr_mb!=p_boot_hdr->tags_addr) && (p_boot_hdr->tags_addr != KERNEL_MBLOCK_LIMIT - DTB_MAX_SIZE))) {
+		pal_log_err("Warning! dtb_kernel_addr (0x%x) is not taken from mb (0x%x)\n", p_boot_hdr->tags_addr, dtb_kernel_addr_mb);
+		assert(0);
+	}
+
+	if ((!kernel_addr_mb) || ((kernel_addr_mb!=p_boot_hdr->kernel_addr) && (p_boot_hdr->kernel_addr != KERNEL_MBLOCK_LIMIT - kernel_sz_mb))) {
+		pal_log_err("Warning! kernel_addr (0x%x) is not taken from mb (0x%x)\n", p_boot_hdr->kernel_addr, kernel_addr_mb);
+		assert(0);
+	}
+
+	if (!skip_ramdisk_check) {
+		if ((!ramdisk_addr_mb) || ((ramdisk_addr_mb!=p_boot_hdr->ramdisk_addr) && (p_boot_hdr->ramdisk_addr != KERNEL_MBLOCK_LIMIT - ROUNDUP(LK_RAMDISK_MAX_SIZE, PAGE_SIZE)))) {
+			pal_log_err("Warning! ramdisk_addr (0x%x) is not taken from mb (0x%x)\n", p_boot_hdr->ramdisk_addr, ramdisk_addr_mb);
+			assert(0);
+		}
+	}
+
+#ifndef DUMMY_MEMORY_LAYOUT
+	/* Use memory_layout.h to check if overlap
+	 * Only need to check address with memory layout when p_boot_hdr->tags/ramdisk_addr is not 0
+	 */
+	if ((dtb_kernel_addr_mb!=LK_DT_BASE) && (p_boot_hdr->tags_addr != KERNEL_MBLOCK_LIMIT - DTB_MAX_SIZE)) {
+		pal_log_err("Warning! compare memory_layout.h with bootimg about DT\n");
+		assert(0);
+	}
+
+	if (!skip_ramdisk_check) {
+		if (((ramdisk_addr_mb!=LK_RAMDISK_BASE) && (p_boot_hdr->ramdisk_addr != KERNEL_MBLOCK_LIMIT - ramdisk_sz_mb)) || (ramdisk_sz_mb > LK_RAMDISK_MAX_SIZE)) {
+			pal_log_err("Warning! compare memory_layout.h with bootimg about ramdisk\n");
+			assert(0);
+		}
+	}
+#endif
+
+	/* update boot_hdr kernel/tags/ramdisk address */
+	p_boot_hdr->kernel_addr = kernel_addr_mb;
+	p_boot_hdr->tags_addr = dtb_kernel_addr_mb;
+	p_boot_hdr->ramdisk_addr = ramdisk_addr_mb;
+
+#endif
+}
+
+
+static void check_hibernation()
+{
+	int hibboot = 0;
+	char tmpbuf[TMPBUF_SIZE];
+
+	hibboot = get_env("hibboot") == NULL ? 0 : atoi(get_env("hibboot"));
+
+	switch (g_boot_mode) {
+	case RECOVERY_BOOT:
+	case FACTORY_BOOT:
+	case ALARM_BOOT:
+#if defined(MTK_KERNEL_POWER_OFF_CHARGING) || defined(MTK_CHARGER_NEW_ARCH)
+	case KERNEL_POWER_OFF_CHARGING_BOOT:
+	case LOW_POWER_OFF_CHARGING_BOOT:
+#endif
+		goto SKIP_HIB_BOOT;
+
+	default:
+		break;
+	}
+
+	if (platform_skip_hibernation && platform_skip_hibernation())
+		goto SKIP_HIB_BOOT;
+
+	if (get_env("resume") != NULL) {
+		if (1 == hibboot) {
+			snprintf(tmpbuf, TMPBUF_SIZE, "%s%s", " resume=", get_env("resume"));
+			cmdline_append(tmpbuf);
+#if defined(MTK_MLC_NAND_SUPPORT)
+			snprintf(tmpbuf, TMPBUF_SIZE, "%s%s", " ubi.mtd=", get_env("ubi_data_mtd"));
+			cmdline_append(tmpbuf);
+#endif
+			//cmdline_append(" no_console_suspend");
+		} else if (0 != hibboot)
+			pal_log_err("resume = %s but hibboot = %s\n", get_env("resume"),
+				get_env("hibboot"));
+	} else
+		pal_log_err("resume = NULL \n");
+
+	return;
+
+SKIP_HIB_BOOT:
+	if (hibboot != 0)
+		if (set_env("hibboot", "0") != 0)
+			pal_log_err("lk_env hibboot set failed!!!\n");
+	if (get_env("resume") != NULL)
+		if (set_env("resume", '\0') != 0)
+			pal_log_err("lk_evn resume set resume failed!!!\n");
+}
+
+#ifdef DEVICE_TREE_SUPPORT
+
+void lk_jump64(u32 addr, u32 arg1, u32 arg2, u32 arg3)
+{
+	pal_log_err("\n[LK]jump to K64 0x%x\n", addr);
+	pal_log_info("smc jump\n");
+	jumparch64_smc(addr, arg1, arg2, arg3);
+	panic("%s Fail to enter EL1\n", __func__);
+}
+
+void memcpy_u8(unsigned char *dest, unsigned char *src, unsigned int size)
+{
+	unsigned int i;
+
+	for (i = 0; i < size; i++)
+		*(dest + i) = *(src + i);
+}
+
+extern bool decompress_kernel(unsigned char *in, void *out, int inlen,
+			      int outlen);
+
+#if defined(MTK_GOOGLE_TRUSTY_SUPPORT)
+int trusty_dts_append(void *fdt)
+{
+	int offset, ret = 0;
+	int nodeoffset = 0;
+	unsigned int trusty_reserved_mem[4] = {0};
+
+	offset = fdt_path_offset(fdt, "/reserved-memory");
+	nodeoffset = fdt_add_subnode(fdt, offset, "trusty-reserved-memory");
+	if (nodeoffset < 0) {
+		dprintf(CRITICAL,
+			"Warning: can't add trusty-reserved-memory node in device tree\n");
+		return 1;
+	}
+	ret = fdt_setprop_string(fdt, nodeoffset, "compatible",
+				 "mediatek,trusty-reserved-memory");
+	if (ret) {
+		dprintf(CRITICAL,
+			"Warning: can't add trusty compatible property in device tree\n");
+		return 1;
+	}
+	ret = fdt_setprop(fdt, nodeoffset, "no-map", NULL, 0);
+	if (ret) {
+		dprintf(CRITICAL, "Warning: can't add trusty no-map property in device tree\n");
+		return 1;
+	}
+	trusty_reserved_mem[0] = 0;
+	trusty_reserved_mem[1] = (u32)cpu_to_fdt32(g_boot_arg->tee_reserved_mem.start);
+	trusty_reserved_mem[2] = 0;
+	trusty_reserved_mem[3] = (u32)cpu_to_fdt32(g_boot_arg->tee_reserved_mem.size);
+	ret = fdt_setprop(fdt, nodeoffset, "reg", trusty_reserved_mem,
+			  sizeof(unsigned int) * 4);
+	if (ret) {
+		dprintf(CRITICAL, "Warning: can't add trusty reg property in device tree\n");
+		return 1;
+	}
+	dprintf(CRITICAL, "trusty-reserved-memory is appended (0x%llx, 0x%llx)\n",
+		g_boot_arg->tee_reserved_mem.start, g_boot_arg->tee_reserved_mem.size);
+
+	return ret;
+}
+#endif
+
+void get_reboot_reason(unsigned int boot_reason)
+{
+	unsigned int rc_wdt_status;
+	unsigned int rc_exp_type;
+
+
+	switch (boot_reason) {
+		case BR_WDT_BY_PASS_PWK: /*by pass mode have more detail reboot reason*/
+			if (ram_console_get_wdt_status(&rc_wdt_status) && ram_console_get_exp_type(&rc_exp_type)) {
+				pal_log_err("rc_wdt_status = %d, rc_exp_type = %d\n", rc_wdt_status, rc_exp_type);
+				switch (rc_exp_type) { /* first check exception type*/
+					case AEE_EXP_TYPE_HWT:
+						cmdline_append("androidboot.bootreason=Watchdog");
+						return;
+
+					case AEE_EXP_TYPE_KE:
+					case AEE_EXP_TYPE_NESTED_PANIC:
+						cmdline_append("androidboot.bootreason=kernel_panic");
+						return;
+
+					case AEE_EXP_TYPE_HANG_DETECT:
+						cmdline_append("androidboot.bootreason=hang_detect");
+						return;
+
+					case AEE_EXP_TYPE_SMART_RESET:
+						cmdline_append("androidboot.bootreason=mrdump");
+						return;
+
+					case AEE_EXP_TYPE_LK_CRASH:
+						cmdline_append("androidboot.bootreason=lk_crash");
+						return;
+
+					default: /* check wdt status */
+						if ((rc_wdt_status & 0x01) == 0x01) {
+							cmdline_append("androidboot.bootreason=HW_reboot");
+							return;
+						} else if ((rc_wdt_status & 0x08) == 0x08) {
+							cmdline_append("androidboot.bootreason=SPM_Thermal_reboot");
+							return;
+						} else if ((rc_wdt_status & 0x10) == 0x10) {
+							cmdline_append("androidboot.bootreason=SPM_reboot");
+							return;
+						} else if ((rc_wdt_status & 0x20) == 0x20) {
+							cmdline_append("androidboot.bootreason=Thermal_reboot");
+							return;
+						} else if ((rc_wdt_status & 0x80) == 0x80) {
+							cmdline_append("androidboot.bootreason=security_reboot");
+							return;
+						} else if ((rc_wdt_status & 0x400) == 0x400) {
+							cmdline_append("androidboot.bootreason=SSPM_reboot");
+							return;
+						} else if ((rc_wdt_status & 0x800) == 0x800) {
+							cmdline_append("androidboot.bootreason=PMIC_cold_reboot");
+							return;
+						}
+				}
+			} /* else to default reboot reason */
+			break;
+		case BR_2SEC_REBOOT:
+			cmdline_append("androidboot.bootreason=2sec_reboot");
+			return;
+		case BR_USB:
+			cmdline_append("androidboot.bootreason=usb");
+			return;
+		case BR_POWER_EXC:
+			cmdline_append("androidboot.bootreason=ocp");
+			return;
+		case BR_LONG_POWKEY:
+			cmdline_append("androidboot.bootreason=reboot_longkey");
+			return;
+		case BR_RTC:
+			cmdline_append("androidboot.bootreason=rtc");
+			return;
+		case BR_POWER_LOSS:
+			cmdline_append("androidboot.bootreason=power_loss");
+			return;
+		case BR_WDT:
+			cmdline_append("androidboot.bootreason=wdt");
+			return;
+		case BR_TOOL_BY_PASS_PWK:
+			cmdline_append("androidboot.bootreason=tool_by_pass_pwk");
+			return;
+		case BR_WDT_SW:
+			cmdline_append("androidboot.bootreason=wdt_sw");
+			return;
+		case BR_WDT_HW:
+			cmdline_append("androidboot.bootreason=wdt_hw");
+			return;
+		case BR_UNKNOWN:
+			cmdline_append("androidboot.bootreason=unknow_reboot");
+			return;
+		case BR_POWER_KEY:
+			cmdline_append("androidboot.bootreason=PowerKey");
+			return;
+		case BR_REBOOT_EXCEPTION:
+			cmdline_append("androidboot.bootreason=RebootException");
+			return;
+	}
+	/* default is soft reboot*/
+	cmdline_append("androidboot.bootreason=reboot");
+}
+
+int boot_linux_fdt(void *kernel, unsigned *tags,
+		   unsigned machtype,
+		   void *ramdisk, unsigned ramdisk_sz)
+{
+	void *fdt = tags;
+	int ret;
+	int offset;
+	char tmpbuf[TMPBUF_SIZE];
+	dt_dram_info mem_reg_property[128];
+
+	int i;
+	void (*entry)(unsigned, unsigned, unsigned *) = kernel;
+	void *kernel_target_addr = kernel;
+	unsigned int lk_t = 0;
+	unsigned int boot_reason = 0;
+	char *ptr;
+	char spare[FDT_SPARE_SIZE],	/* SPARE_SIZE = BUFF_SIZE + CHCKER_SIZE */
+	     *buf 	= spare,
+		*checker 	= (spare + FDT_BUFF_SIZE);
+	unsigned int zimage_size = 0;
+	u32 seed[2];
+	const void *seedp, *kaslr_status;
+	const void *kmemleak_status;
+	int seed_len, status_len;
+	uint32_t kernel_load_addr;
+
+#ifdef ALLOCATE_FROM_MBLOCK
+	if (!kernel_sz_mb)
+		panic("kernel_sz_mb should not be zero\n");
+#else
+	u32 kernel_sz_mb = LK_KERNEL_64_MAX_SIZE;
+#endif
+
+
+	kernel_load_addr = get_kernel_addr();
+	if (g_is_64bit_kernel) {
+		zimage_size = get_kernel_real_sz();
+
+		pal_log_info("64 bits kernel\n");
+		pal_log_err("kernel real kernel_sz=0x%08x\n", zimage_size);
+
+		if ((uint32_t)kernel_target_addr & 0x7FFFF) {
+			panic("64 bit kernel can't boot at 0x%08x\n",
+					(uint32_t)kernel_target_addr);
+		}
+		pal_log_info("zimage_size=0x%08x, zimage_size=0x%08x\n",
+				zimage_size, zimage_size);
+		pal_log_info("decompress kernel image...\n");
+
+		/* for 64bit decompreesed size.
+		 * LK start: 0x41E00000, Kernel Start: 0x40080000
+		 * Max is 0x41E00000 - 0x40080000 = 0x1D80000.
+		 * using 0x1C00000=28MB for decompressed kernel image size */
+		if (decompress_kernel((unsigned char *)(kernel_load_addr),
+				      (void *)kernel_target_addr, (int)zimage_size,
+				      (int)kernel_sz_mb)) {
+			panic("decompress kernel image fail!!!\n");
+		}
+	} else {
+		pal_log_info("32 bits kernel\n");
+		zimage_size = get_kernel_real_sz();
+		memcpy(kernel_target_addr, (void *)kernel_load_addr, zimage_size);
+		wake_up_iothread();
+		wait_for_iothread();
+	}
+	strncpy(checker, FDT_BUFF_END, FDT_CHECKER_SIZE - 1);
+	checker[FDT_CHECKER_SIZE - 1] = '\0';
+
+	extern int target_fdt_jtag(void *fdt)__attribute__((weak));
+	if (target_fdt_jtag)
+		target_fdt_jtag(fdt);
+
+	extern int target_fdt_model(void *fdt)__attribute__((weak));
+	if (target_fdt_model)
+		target_fdt_model(fdt);
+
+	extern int target_fdt_cpus(void *fdt)__attribute__((weak));
+	if (target_fdt_cpus)
+		target_fdt_cpus(fdt);
+
+	load_images(g_boot_mode);
+
+#ifdef MTK_SECURITY_ANTI_ROLLBACK
+#ifdef MTK_OTP_FRAMEWORK_V2
+		if (g_boot_mode == NORMAL_BOOT || g_boot_mode == RECOVERY_BOOT) {
+			ret = sec_otp_ver_update(g_boot_mode);
+		}
+#else
+		if (g_boot_mode == NORMAL_BOOT) {
+			ret = sec_otp_ver_update(g_boot_mode);
+			imgver_not_sync_warning(g_boot_arg->pl_imgver_status, ret);
+		}
+#endif
+#endif
+
+	extern int setup_mem_property_use_mblock_info(dt_dram_info *,
+			size_t) __attribute__((weak));
+	if (setup_mem_property_use_mblock_info) {
+		ret = setup_mem_property_use_mblock_info(
+			      &mem_reg_property[0],
+			      sizeof(mem_reg_property) / sizeof(dt_dram_info));
+		if (ret) {
+			PAL_ASSERT(0);
+			return FALSE;
+		}
+	} else {
+		for (i = 0; i < g_nr_bank; ++i) {
+			unsigned int fb_size = (i == g_nr_bank - 1) ? g_fb_size : 0;
+
+#ifndef MTK_LM_MODE
+			mem_reg_property[i].start_hi = cpu_to_fdt32(0);
+			mem_reg_property[i].start_lo = cpu_to_fdt32(bi_dram[i].start);
+			mem_reg_property[i].size_hi = cpu_to_fdt32(0);
+			mem_reg_property[i].size_lo = cpu_to_fdt32(bi_dram[i].size - fb_size);
+
+#else
+			mem_reg_property[i].start_hi = cpu_to_fdt32(bi_dram[i].start >> 32);
+			mem_reg_property[i].start_lo = cpu_to_fdt32(bi_dram[i].start);
+			mem_reg_property[i].size_hi = cpu_to_fdt32((bi_dram[i].size - fb_size) >> 32);
+			mem_reg_property[i].size_lo = cpu_to_fdt32(bi_dram[i].size - fb_size);
+
+#endif
+			pal_log_info(" mem_reg_property[%d].start_hi = 0x%08X\n", i,
+				mem_reg_property[i].start_hi);
+			pal_log_info(" mem_reg_property[%d].start_lo = 0x%08X\n", i,
+				mem_reg_property[i].start_lo);
+			pal_log_info(" mem_reg_property[%d].size_hi = 0x%08X\n", i,
+				mem_reg_property[i].size_hi);
+			pal_log_info(" mem_reg_property[%d].size_lo = 0x%08X\n", i,
+				mem_reg_property[i].size_lo);
+		}
+	}
+
+	extern int set_fdt_emi_info(void *fdt)__attribute((weak));
+	if (set_fdt_emi_info) {
+		ret = set_fdt_emi_info(fdt);
+		if (ret)
+			pal_log_err("ERROR: EMI info incorrect\n");
+	}
+
+	extern int set_fdt_dramc(void *fdt)__attribute((weak));
+		if (set_fdt_dramc) {
+			ret = set_fdt_dramc(fdt);
+		if (ret)
+			pal_log_err("ERROR: DRAMC info incorrect\n");
+	}
+
+	extern int set_fdt_pll(void *fdt)__attribute((weak));
+	if (set_fdt_pll) {
+		ret = set_fdt_pll(fdt);
+		if (ret)
+			pal_log_err("ERROR: PLL info incorrect\n");
+	}
+
+	extern int target_fdt_dram_dummy_read(void *fdt,
+					      unsigned int rank_num)__attribute__((weak));
+	if (target_fdt_dram_dummy_read) {
+		ret = target_fdt_dram_dummy_read(fdt, g_nr_bank);
+		if (ret)
+			pal_log_err("ERROR: DRAM dummy read address incorrect\n");
+	}
+
+	extern int set_fdt_dbg_info(void *fdt)__attribute__((weak));
+	if (set_fdt_dbg_info) {
+		ret = set_fdt_dbg_info(fdt);
+		if (ret)
+			pal_log_err("ERROR: debug info base and size incorrect\n");
+	}
+	/*
+	 * if there is no memory node exist
+	 * we will create a new one
+	 */
+#if defined(MBLOCK_LIB_SUPPORT) || defined(NEW_MEMORY_RESERVED_MODEL)
+	{
+		int nodeoffset;
+		offset = fdt_path_offset(fdt, "/memory");
+		if (offset < 0) {
+			offset = fdt_path_offset(fdt, "/");
+			if (offset < 0) {
+				panic("ERROR: root node search failed , while(1)\n");
+			}
+			nodeoffset = fdt_add_subnode(fdt, offset, "memory");
+			if (nodeoffset < 0) {
+				panic("ERROR: add subnode memory failed, while(1)\n");
+			} else {
+				ret = fdt_setprop_string(fdt, nodeoffset, "device_type", "memory");
+				pal_log_err("DTS:/memory node is not found create new memory node\n");
+			}
+		}
+	}
+
+	offset = fdt_path_offset(fdt, "/memory");
+	if (offset < 0) {
+		panic("ERROR: /memory node not exist, while(1)\n");
+	}
+#endif
+
+	extern int get_mblock_num(void) __attribute__((weak));
+
+#if defined(MBLOCK_LIB_SUPPORT)
+#if	defined(MBLOCK_LIB_SUPPORT) && (MBLOCK_EXPAND(MBLOCK_LIB_SUPPORT) == MBLOCK_EXPAND(2))
+	pal_log_err("PASS memory DTS node\n");
+	ret = fdt_setprop(fdt, offset, "reg", mem_reg_property, sizeof(dt_dram_info));
+#else
+	pal_log_err("PASS memory DTS node\n");
+	ret = fdt_setprop(fdt, offset, "reg", mem_reg_property,
+			  ((int)get_mblock_num ? get_mblock_num() : g_nr_bank) * sizeof(dt_dram_info));
+#endif
+#else
+#if defined(NEW_MEMORY_RESERVED_MODEL)
+	pal_log_err("PASS memory DTS node\n");
+	ret = fdt_setprop(fdt, offset, "reg", mem_reg_property,
+			  ((int)get_mblock_num ? get_mblock_num() : g_nr_bank) * sizeof(dt_dram_info));
+#endif
+#endif
+	if (ret) {
+		assert(0);
+		return FALSE;
+	}
+
+	if (platform_atag_append) {
+		ret = platform_atag_append(fdt);
+		if (ret) {
+			assert(0);
+			return FALSE;
+		}
+	}
+#ifdef MBLOCK_LIB_SUPPORT
+	ret = fdt_memory_append(fdt);
+	if (ret) {
+		assert(0);
+		return FALSE;
+	}
+#endif
+
+#if defined(MTK_GOOGLE_TRUSTY_SUPPORT)
+	ret = trusty_dts_append(fdt);
+	if (ret) {
+		assert(0);
+		return FALSE;
+	}
+#endif
+
+	offset = fdt_path_offset(fdt, "/chosen");
+	if (offset < 0) {
+		pal_log_err("Error: can't search chosen node in device tree\n");
+	}
+
+	kmemleak_status = fdt_getprop(fdt, offset,
+					"kmemleak-status", &status_len);
+	if (kmemleak_status && !strcmp(kmemleak_status, "okay"))
+		cmdline_append("kmemleak=on");
+
+	ret = fdt_setprop_cell(fdt, offset, "linux,initrd-start",
+			       (unsigned int) ramdisk);
+	if (ret) {
+		assert(0);
+		return FALSE;
+	}
+	ret = fdt_setprop_cell(fdt, offset, "linux,initrd-end",
+			       (unsigned int)ramdisk + ramdisk_sz);
+	if (ret) {
+		assert(0);
+		return FALSE;
+	}
+
+	ptr = (char *)target_atag_boot((unsigned *)buf);
+	ret = fdt_setprop(fdt, offset, "atag,boot", buf, ptr - buf);
+	if (ret) {
+		assert(0);
+		return FALSE;
+	}
+
+	seedp = fdt_getprop(fdt, offset, "kaslr-seed", &seed_len);
+	/* get random kaslr-seed if it is defined in the dtb */
+	if (seedp) {
+		if (seed_len != sizeof(u64)) {
+			pal_log_err("incorrect kaslr-seed length=%d\n",
+				seed_len);
+			assert(0);
+			return FALSE;
+		}
+#ifdef MTK_SECURITY_SW_SUPPORT
+		get_rnd(&seed[0]);
+		get_rnd(&seed[1]);
+#else
+		seed[0] = seed[1] = 0;
+		cmdline_append("nokaslr");
+#endif
+		ret = fdt_setprop(fdt, offset, "kaslr-seed", seed, seed_len);
+		if (ret) {
+			assert(0);
+			return FALSE;
+		}
+
+		kaslr_status = fdt_getprop(fdt, offset,
+				"kaslr-status", &status_len);
+		if (kaslr_status && !strcmp(kaslr_status, "disabled"))
+			cmdline_append("nokaslr");
+	}
+
+#if defined(MTK_DLPT_SUPPORT)
+	ptr = (char *)target_atag_imix_r((unsigned *)buf);
+	ret = fdt_setprop(fdt, offset, "atag,imix_r", buf, ptr - buf);
+	if (ret) {
+		assert(0);
+		return FALSE;
+	}
+#endif
+	snprintf(buf, FDT_BUFF_SIZE, "%d", fg_swocv_v);
+	ptr = buf + strlen(buf);
+	ret = fdt_setprop(fdt, offset, "atag,fg_swocv_v", buf, ptr - buf);
+	if (ret) {
+		assert(0);
+		return FALSE;
+	}
+	pal_log_err("fg_swocv_v buf [%s], [0x%x:0x%x:%d]\n", buf, (unsigned)buf,
+		(unsigned)ptr, ptr - buf);
+
+	snprintf(buf, FDT_BUFF_SIZE, "%d", fg_swocv_i);
+	ptr = buf + strlen(buf);
+	ret = fdt_setprop(fdt, offset, "atag,fg_swocv_i", buf, ptr - buf);
+	if (ret) {
+		assert(0);
+		return FALSE;
+	}
+	pal_log_err("fg_swocv_i buf [%s], [0x%x:0x%x:%d]\n", buf, (unsigned)buf,
+		(unsigned)ptr, ptr - buf);
+
+	snprintf(buf, FDT_BUFF_SIZE, "%d", shutdown_time);
+	ptr = buf + strlen(buf);
+	ret = fdt_setprop(fdt, offset, "atag,shutdown_time", buf, ptr - buf);
+	if (ret) {
+		assert(0);
+		return FALSE;
+	}
+	pal_log_err("shutdown_time buf [%s], [0x%x:0x%x:%d]\n", buf,
+		(unsigned)buf, (unsigned)ptr, ptr - buf);
+
+	ram_console_dts_written(fdt);
+
+	snprintf(buf, FDT_BUFF_SIZE, "%d", boot_voltage);
+	ptr = buf + strlen(buf);
+	ret = fdt_setprop(fdt, offset, "atag,boot_voltage", buf, ptr - buf);
+	if (ret) {
+		assert(0);
+		return FALSE;
+	}
+	pal_log_err("boot_voltage buf [%s], [0x%x:0x%x:%d]\n", buf, (unsigned)buf,
+		(unsigned)ptr, ptr - buf);
+
+	snprintf(buf, FDT_BUFF_SIZE, "%d", two_sec_reboot);
+	ptr = buf + strlen(buf);
+	ret = fdt_setprop(fdt, offset, "atag,two_sec_reboot", buf, ptr - buf);
+	if (ret) {
+		assert(0);
+		return FALSE;
+	}
+	pal_log_err("boot_voltage buf [%s], [0x%x:0x%x:%d]\n", buf, (unsigned)buf,
+		(unsigned)ptr, ptr - buf);
+
+	ptr = (char *)target_atag_mem((unsigned *)buf);
+	ret = fdt_setprop(fdt, offset, "atag,mem", buf, ptr - buf);
+	if (ret) {
+		assert(0);
+		return FALSE;
+	}
+
+	if (target_atag_partition_data) {
+		ptr = (char *)target_atag_partition_data((unsigned *)buf);
+		if (ptr != buf) {
+			ret = fdt_setprop(fdt, offset, "atag,mem", buf, ptr - buf);
+			if (ret) {
+				assert(0);
+				return FALSE;
+			}
+		}
+	}
+#if !(defined(MTK_UFS_SUPPORT) || defined(MTK_EMMC_SUPPORT))
+	if (target_atag_nand_data) {
+		ptr = (char *)target_atag_nand_data((unsigned *)buf);
+		if (ptr != buf) {
+			ret = fdt_setprop(fdt, offset, "atag,mem", buf, ptr - buf);
+			if (ret) {
+				assert(0);
+				return FALSE;
+			}
+		}
+	}
+#endif
+	extern int spislv_write_param_to_dt(void *fdt)__attribute__((weak));
+	spislv_write_param_to_dt(fdt);
+
+	extern unsigned int *target_atag_vcore_dvfs(unsigned * ptr)__attribute__((
+				weak));
+	if (target_atag_vcore_dvfs) {
+		ptr = (char *)target_atag_vcore_dvfs((unsigned *)buf);
+		ret = fdt_setprop(fdt, offset, "atag,vcore_dvfs", buf, ptr - buf);
+		if (ret) {
+			assert(0);
+			return FALSE;
+		}
+	} else
+		pal_log_err("Not Support VCORE DVFS\n");
+
+	//some platform might not have this function, use weak reference for
+	extern unsigned *target_atag_dfo(unsigned * ptr)__attribute__((weak));
+	if (target_atag_dfo) {
+		ptr = (char *)target_atag_dfo((unsigned *)buf);
+		ret = fdt_setprop(fdt, offset, "atag,dfo", buf, ptr - buf);
+		if (ret) {
+			assert(0);
+			return FALSE;
+		}
+	}
+
+	if (g_boot_mode == META_BOOT || g_boot_mode == ADVMETA_BOOT ||
+	    g_boot_mode == ATE_FACTORY_BOOT || g_boot_mode == FACTORY_BOOT) {
+		ptr = (char *)target_atag_meta((unsigned *)buf);
+		ret = fdt_setprop(fdt, offset, "atag,meta", buf, ptr - buf);
+		if (ret) {
+			assert(0);
+			return FALSE;
+		}
+		unsigned int meta_com_id = g_boot_arg->meta_com_id;
+		if (g_boot_mode == META_BOOT) {
+			int adb = !(meta_com_id & 0x0001);
+			int elt = !!(meta_com_id & 0x0004);
+
+			if (!adb && !elt) {
+				/*only META*/
+				cmdline_append("androidboot.usbconfig=1");
+			} else if (adb && !elt) {
+				/*META + ADB*/
+				cmdline_append("androidboot.usbconfig=0");
+			} else if (!adb && elt) {
+				/*META + ELT*/
+				cmdline_append("androidboot.usbconfig=2");
+			} else {
+				/*META + ELT + ADB*/
+				cmdline_append("androidboot.usbconfig=3");
+			}
+		} else {
+			int adb = !(meta_com_id & 0x0001);
+			if (!adb) {
+				cmdline_append("androidboot.usbconfig=1");
+			} else {
+				cmdline_append("androidboot.usbconfig=0");
+			}
+		}
+		if (g_boot_mode == META_BOOT || g_boot_mode == ADVMETA_BOOT) {
+			snprintf(tmpbuf, TMPBUF_SIZE, "androidboot.init_rc=%s", META_INIT_RC);
+			cmdline_append(tmpbuf);
+
+			if ((meta_com_id & 0x0002) != 0)
+				cmdline_append("androidboot.mblogenable=0");
+
+			else
+				cmdline_append("androidboot.mblogenable=1");
+		} else {
+			snprintf(tmpbuf, TMPBUF_SIZE, "androidboot.init_rc=%s", FACTORY_INIT_RC);
+			cmdline_append(tmpbuf);
+		}
+	}
+
+	ptr = (char *)target_atag_devinfo_data((unsigned *)buf);
+	ret = fdt_setprop(fdt, offset, "atag,devinfo", buf, ptr - buf);
+	if (ret) {
+		assert(0);
+		return FALSE;
+	}
+
+#ifndef MACH_FPGA_NO_DISPLAY
+	ptr = (char *)target_atag_videolfb((unsigned *)buf, FDT_BUFF_SIZE);
+	ret = fdt_setprop(fdt, offset, "atag,videolfb", buf, ptr - buf);
+	if (ret) {
+		assert(0);
+		return FALSE;
+	}
+
+#if (MTK_DUAL_DISPLAY_SUPPORT == 2)
+	ptr = (char *)target_atag_ext_videolfb((unsigned *)buf);
+	ret = fdt_setprop(fdt, offset, "atag,ext_videolfb", buf, ptr - buf);
+	if (ret) {
+		assert(0);
+		return FALSE;
+	}
+#endif
+#else
+
+	extern int mt_disp_config_frame_buffer(void *fdt)__attribute__((weak));
+	if (mt_disp_config_frame_buffer)
+		ret = mt_disp_config_frame_buffer(fdt);
+
+#endif
+
+	extern int lastpc_decode(void *fdt)__attribute__((weak));
+	if (lastpc_decode) {
+		ret = lastpc_decode(fdt);
+		if (ret) {
+			assert(0);
+			return FALSE;
+		}
+	}
+
+	if (target_atag_mdinfo) {
+		ptr = (char *)target_atag_mdinfo((unsigned *)buf);
+		ret = fdt_setprop(fdt, offset, "atag,mdinfo", buf, ptr - buf);
+		if (ret) {
+			assert(0);
+			return FALSE;
+		}
+	} else
+		pal_log_err("DFO_MODEN_INFO Only support in MT6582/MT6592\n");
+
+	ccci_update_lk_arg_info_to_dt(buf, fdt, offset);
+
+	extern unsigned int *target_atag_ptp(unsigned * ptr)__attribute__((weak));
+	if (target_atag_ptp) {
+		ptr = (char *)target_atag_ptp((unsigned *)buf);
+		ret = fdt_setprop(fdt, offset, "atag,ptp", buf, ptr - buf);
+		if (ret) {
+			assert(0);
+			return FALSE;
+		} else
+			pal_log_err("Create PTP DT OK\n");
+	} else
+		pal_log_err("PTP_INFO Only support in MT6795\n");
+
+	if (target_atag_masp_data) {
+		ptr = (char *)target_atag_masp_data((unsigned *)buf);
+		ret = fdt_setprop(fdt, offset, "atag,masp", buf, ptr - buf);
+		if (ret) {
+			assert(0);
+			return FALSE;
+		} else
+			pal_log_err("create masp atag OK\n");
+	} else
+		pal_log_err("masp atag not support in this platform\n");
+
+	extern unsigned int *target_atag_tee(unsigned * ptr)__attribute__((weak));
+	if (target_atag_tee) {
+		ptr = (char *)target_atag_tee((unsigned *)buf);
+		ret = fdt_setprop(fdt, offset, "tee_reserved_mem", buf, ptr - buf);
+		if (ret) {
+			assert(0);
+			return FALSE;
+		}
+	} else
+		pal_log_err("tee_reserved_mem not supported\n");
+
+	extern unsigned int *target_atag_isram(unsigned * ptr)__attribute__((weak));
+	if (target_atag_isram) {
+		ptr = (char *)target_atag_isram((unsigned *)buf);
+		ret = fdt_setprop(fdt, offset, "non_secure_sram", buf, ptr - buf);
+		if (ret) {
+			assert(0);
+			return FALSE;
+		}
+	} else
+		pal_log_err("non_secure_sram not supported\n");
+
+	if(disp_lcm_fill_lcm_dts_phandle) {
+		int panel_index = disp_lcm_get_dts_panel_index();
+		if(disp_lcm_fill_lcm_dts_phandle(fdt, panel_index) != 0) {
+		    pal_log_err("set dsi panel index to dtb failed.");
+		}
+	}
+
+	if (!has_set_p2u) {
+		switch (eBuildType) {
+		case BUILD_TYPE_USER:
+			if (((g_boot_mode == META_BOOT) && is_meta_log_disable &&
+#ifdef LOG_STORE_SUPPORT
+			    (is_meta_log_disable() == 0)) || g_boot_arg->log_dynamic_switch)
+#else
+		      (is_meta_log_disable() == 0)))
+#endif
+				cmdline_append("mtk_printk_ctrl.disable_uart=0");
+			else
+				cmdline_append("mtk_printk_ctrl.disable_uart=1");
+			break;
+
+		case BUILD_TYPE_USERDEBUG:
+			if ((g_boot_mode == META_BOOT) && is_meta_log_disable &&
+#ifdef LOG_STORE_SUPPORT
+			    (is_meta_log_disable() == 1) && (g_boot_arg->log_dynamic_switch == 0))
+#else
+			    (is_meta_log_disable() == 1))
+#endif
+				cmdline_append("mtk_printk_ctrl.disable_uart=1 slub_debug=O");
+#ifdef LOG_STORE_SUPPORT
+			else if (boot_ftrace && g_boot_arg->log_dynamic_switch == 0)
+#else
+			else if (boot_ftrace)
+#endif
+				cmdline_append("mtk_printk_ctrl.disable_uart=1 slub_debug=-");
+			else
+				cmdline_append("mtk_printk_ctrl.disable_uart=0");
+			break;
+
+		case BUILD_TYPE_ENG:
+			if ((g_boot_mode == META_BOOT) && is_meta_log_disable &&
+			    (is_meta_log_disable() == 1))
+				cmdline_append("mtk_printk_ctrl.disable_uart=1 slub_debug=O");
+			else
+				cmdline_append("mtk_printk_ctrl.disable_uart=0 ddebug_query=\"file *mediatek* +p ; file *gpu* =_\"");
+			break;
+
+		default:
+			assert(0);
+			break;
+		}
+	}
+	/*Append pre-loader boot reason to kernel command line*/
+#ifdef MTK_KERNEL_POWER_OFF_CHARGING
+	if (g_boot_reason_change)
+		boot_reason = BR_WDT_BY_PASS_PWK;
+
+	else
+#endif
+	{
+		boot_reason = g_boot_arg->boot_reason;
+	}
+
+	/* Append androidboot.serialno=xxxxyyyyzzzz in cmdline */
+	snprintf(tmpbuf, TMPBUF_SIZE, "%s%s", "androidboot.serialno=", sn_buf);
+	cmdline_append(tmpbuf);
+
+	get_reboot_reason(boot_reason);
+
+	extern unsigned int *target_commandline_force_gpt(char *cmd)__attribute__((
+				weak));
+	if (target_commandline_force_gpt)
+		target_commandline_force_gpt((char *)cmdline_get());
+
+	extern void ccci_append_tel_fo_setting(char *cmdline)__attribute__((weak));
+	if (ccci_append_tel_fo_setting)
+		ccci_append_tel_fo_setting((char *)cmdline_get());
+
+	if (eBuildType == BUILD_TYPE_ENG)
+		cmdline_append("initcall_debug=1");
+
+	extern int dfd_set_base_addr(void *fdt)__attribute__((weak));
+	if (dfd_set_base_addr) {
+		ret = dfd_set_base_addr(fdt);
+		if (ret)
+			pal_log_err("[DFD] failed to get base address (%d)\n", ret);
+	}
+
+	extern unsigned int get_usb2jtag(void) __attribute__((weak));
+	extern unsigned int set_usb2jtag(unsigned int en)  __attribute__((weak));
+	if (get_usb2jtag) {
+		if (get_usb2jtag() == 1)
+			cmdline_append("usb2jtag_mode=1");
+		else
+			cmdline_append("usb2jtag_mode=0");
+	}
+
+	check_hibernation();
+
+	/*DTS memory will be modified during lk boot process
+	 * so we need to put the cmdline in the last mile*/
+	mrdump_init(fdt);
+
+#if 0
+	ptr = (char *)target_atag_commandline((u8 *)buf, FDT_BUFF_SIZE,
+					      (const char *)cmdline_get());
+	ret = fdt_setprop(fdt, offset, "atag,cmdline", buf, ptr - buf);
+	if (ret) {
+		assert(0);
+		return FALSE;
+	}
+#else
+
+	dprintf(INFO, "target_atag_commandline skip for not used\n"); //skip copy atag for kernel not used
+
+#endif
+	/* send kernel the dtbo_idx upon overlay success */
+	snprintf(tmpbuf, TMPBUF_SIZE, "androidboot.dtb_idx=0 androidboot.dtbo_idx=%d", get_dtbo_index());
+	cmdline_append(tmpbuf);
+
+	ret = fdt_setprop_string(fdt, offset, "bootargs", (char *)cmdline_get());
+	if (ret) {
+		assert(0);
+		return FALSE;
+	}
+	ptr = (char *)target_atag_chipid((unsigned *)buf);
+	if (ptr != NULL) {
+		ret = fdt_setprop(fdt, offset, "atag,chipid", buf, ptr - buf);
+		if (ret) {
+			dprintf(CRITICAL, "fail to set property chip id in fdt!\n");
+		}
+	} else
+		dprintf(CRITICAL, "target_atag_chipid return NULL pointer!\n");
+
+	extern int *target_fdt_firmware(void *fdt, char *serialno)__attribute__((weak));
+	if (target_fdt_firmware)
+		target_fdt_firmware(fdt, sn_buf);
+
+	/* This depends on target_fdt_firmware, must after target_fdt_firmware */
+	ccci_update_md_opt_to_fdt_firmware(fdt);
+	/* Return the mb before stepping into kernel */
+	mboot_free_bootimg_from_mblock();
+	mboot_free_lk_scratch_from_mblock();
+	free_bootimgs();
+	mt_free_logo_from_mblock();
+	mrdump_reserve_memory();
+	heap_deinit();
+
+#if defined(MBLOCK_LIB_SUPPORT)
+#if	defined(MBLOCK_LIB_SUPPORT) && (MBLOCK_EXPAND(MBLOCK_LIB_SUPPORT) == MBLOCK_EXPAND(2))
+	/* this should be proper place for mblock memory santiy check*/
+	ret = mblock_sanity_check(fdt, &g_boot_arg->mblock_info,
+				  &g_boot_arg->orig_dram_info);
+	if (ret) {
+		assert(0);
+		return FALSE;
+	}
+
+	ret = mblock_reserved_append(fdt);
+	if (ret) {
+		assert(0);
+		return FALSE;
+	}
+#endif
+#endif
+
+	ccci_create_MD_attr_dt_node(fdt);
+
+	/* bootprof: pl/lk/logo_lk_t boot time via Device Tree */
+	/* Last execution time of LK */
+	ret = boot_time_via_dt(fdt, &lk_t);
+	if (ret) {
+		assert(0);
+		return FALSE;
+	}
+
+	PROFILING_PRINTF("1st logo takes %d ms", logo_lk_t);
+	PROFILING_PRINTF("boot_time takes %d ms", lk_t);
+
+	ret = fdt_pack(fdt);
+	if (ret) {
+		assert(0);
+		return FALSE;
+	}
+
+	pal_log_err("booting linux @ %p, ramdisk @ %p (%d)\n",
+		kernel, ramdisk, ramdisk_sz);
+
+	if (strncmp(checker, FDT_BUFF_END, FDT_CHECKER_SIZE) != 0) {
+		pal_log_err("ERROR: fdt buff overflow\n");
+		assert(0);
+		return FALSE;
+	}
+	/*Prevent the system jumps to Kernel if we unplugged Charger/USB before*/
+	if (kernel_charging_boot) {
+		if (kernel_charging_boot() == -1) {
+			pal_log_err(
+				"[%s] Unplugged Usb/Charger in Kernel Charging Mode Before Jumping to Kernel, Power Off\n",
+				__func__);
+#ifndef NO_POWER_OFF
+#ifdef MTK_PMIC_POWER_OFF
+			mt_power_off();
+#else
+			mt6575_power_off();
+#endif
+#endif
+		}
+		if (kernel_charging_boot() == 1) {
+			if (pmic_detect_powerkey()) {
+				pal_log_err(
+					"[%s] PowerKey Pressed in Kernel Charging Mode Before Jumping to Kernel, Reboot Os\n",
+					__func__);
+				//mt65xx_backlight_off();
+				//mt_disp_power(0);
+				mtk_arch_reset(1);
+			}
+		}
+	}
+
+	enter_critical_section();
+	/* do any platform specific cleanup before kernel entry */
+	platform_uninit();
+#ifdef HAVE_CACHE_PL310
+	l2_disable();
+#endif
+
+	arch_disable_cache(UCACHE);
+	arch_disable_mmu();
+
+#ifndef MACH_FPGA
+	extern void platform_sec_post_init(void)__attribute__((weak));
+	if (platform_sec_post_init)
+		platform_sec_post_init();
+#endif
+	pal_log_err("DRAM Rank :%d\n", g_nr_bank);
+	for (i = 0; i < g_nr_bank; i++) {
+#ifndef MTK_LM_MODE
+		pal_log_err("DRAM Rank[%d] Start = 0x%x, Size = 0x%x\n", i,
+			(unsigned int)bi_dram[i].start, (unsigned int)bi_dram[i].size);
+#else
+		pal_log_err("DRAM Rank[%d] Start = 0x%llx, Size = 0x%llx\n", i,
+			bi_dram[i].start, bi_dram[i].size);
+#endif
+	}
+
+#ifdef MBLOCK_LIB_SUPPORT
+	mblock_show_info();
+#endif
+
+	cmdline_print();
+	pal_log_err("lk boot mode = %d\n", g_boot_mode);
+	pal_log_err("lk boot reason = %d\n", boot_reason);
+	pal_log_err("lk finished --> jump to linux kernel %s\n\n",
+		g_is_64bit_kernel ? "64Bit" : "32Bit");
+
+	/*
+	 * Kick watchdog before leaving lk to avoid watchdog reset if
+	 * kernel initialization has longer execution time.
+	 *
+	 * Of course watchdog will still be triggered if kernel hangs
+	 * because watchdog is still alive.
+	 */
+	mtk_timer_deinit();
+	mtk_wdt_set_time_out_value(30);
+	mtk_wdt_restart();
+
+#ifdef USER_LOAD
+	//For not intruding user load, print LK log in a whole here, when triggered.
+	if (g_lk_final_log == RUNTIME_LOG_DEACTIVATED) {
+		g_lk_final_log = RUNTIME_LOG_ACTIVATED;
+		if (current_lk_buf_addr_get && current_buf_addr_get && current_buf_pl_lk_log_size_get) {
+			*(u8 *)(current_buf_addr_get() + current_buf_pl_lk_log_size_get() - 1) = '\0';
+			uart_puts((char *)current_lk_buf_addr_get());
+		}
+	}
+#endif
+
+	if (Debug_log_EMI_MPU)
+		Debug_log_EMI_MPU();
+
+	if (g_is_64bit_kernel) {
+		lk_jump64((u32)entry, (u32)tags, 0, KERNEL_64BITS);
+	} else {
+#ifdef MTK_SMC_K32_SUPPORT
+		lk_jump64((u32)entry, (u32)machtype, (u32)tags, KERNEL_32BITS);
+#else
+		entry(0, machtype, tags);
+#endif
+	}
+	panic("%s Fail to enter EL1\n", __func__);
+	return 0;
+}
+
+
+
+#endif // DEVICE_TREE_SUPPORT
+
+void boot_linux(void *kernel, unsigned *tags,
+		unsigned machtype,
+		void *ramdisk, unsigned ramdisk_sz)
+{
+#ifdef DEVICE_TREE_SUPPORT
+	boot_linux_fdt((void *)kernel, (unsigned *)tags,
+		       machtype,
+		       (void *)ramdisk, ramdisk_sz);
+	panic("%s Fail to enter EL1\n", __func__);
+#endif
+}
+
+#ifdef MTK_AB_OTA_UPDATER
+void get_AB_OTA_param(void)
+{
+	p_AB_suffix = get_suffix();
+	AB_retry_count = get_retry_count(p_AB_suffix);
+	pal_log_err("[%s:%d] p_AB_suffix: %s, AB_retry_count: %d\n", __func__,
+		__LINE__, p_AB_suffix, AB_retry_count);
+}
+
+void get_AB_OTA_name(char *part_name, int size)
+{
+	int ret;
+
+	if (!p_AB_suffix)
+		get_AB_OTA_param();
+	ret = snprintf(part_name, size, "%s%s", part_name, p_AB_suffix);
+
+	if (ret <= 0)
+		pal_log_err("[%s:%d] %s get part_name fail\n", __func__,
+		__LINE__, part_name);
+}
+#endif /* MTK_AB_OTA_UPDATER */
+
+int boot_linux_from_storage(void)
+{
+	int ret = 0;
+	uint32_t kernel_target_addr = 0;
+	uint32_t ramdisk_target_addr = 0;
+	uint32_t tags_target_addr = 0;
+	uint32_t ramdisk_real_sz = 0;
+#if defined(CFG_NAND_BOOT)
+#define CMDLINE_TMP_CONCAT_SIZE 110
+	char cmdline_tmpbuf[CMDLINE_TMP_CONCAT_SIZE];
+#endif
+	switch (g_boot_mode) {
+	case NORMAL_BOOT:
+	case META_BOOT:
+	case ADVMETA_BOOT:
+	case SW_REBOOT:
+	case ALARM_BOOT:
+#ifdef MTK_KERNEL_POWER_OFF_CHARGING
+	case KERNEL_POWER_OFF_CHARGING_BOOT:
+	case LOW_POWER_OFF_CHARGING_BOOT:
+#endif
+		PROFILING_START("load boot image");
+#if defined(CFG_NAND_BOOT)
+		snprintf(cmdline_tmpbuf, CMDLINE_TMP_CONCAT_SIZE, "%s%x%s%x",
+			 NAND_MANF_CMDLINE, nand_flash_man_code, NAND_DEV_CMDLINE, nand_flash_dev_id);
+		cmdline_append(cmdline_tmpbuf);
+#endif
+		ret = load_vfy_boot(BOOTIMG_TYPE_BOOT, CFG_BOOTIMG_LOAD_ADDR);
+		ret = (int)handle_vboot_state(BOOTIMG_TYPE_BOOT);
+		if (ret != STATUS_OK)
+			mtk_arch_reset(1);
+
+		PAL_ASSERT(ret >= 0);
+
+		PROFILING_END();
+		break;
+
+	case RECOVERY_BOOT:
+		/* it's boot.img when system as root is enabled, and is *
+		 * recovery.img when system as root is disabled. *
+		 */
+		PROFILING_START("load recovery image");
+		if (!get_recovery_img_loaded()) {
+			ret = load_vfy_boot(BOOTIMG_TYPE_RECOVERY, CFG_BOOTIMG_LOAD_ADDR);
+			ret = (int)handle_vboot_state(BOOTIMG_TYPE_RECOVERY);
+			if (ret != STATUS_OK)
+				mtk_arch_reset(1);
+			PAL_ASSERT(ret >= 0);
+		}
+		PROFILING_END();
+		break;
+
+	case FACTORY_BOOT:
+	case ATE_FACTORY_BOOT:
+		/* it's boot.img, we don't have standalone factory image now */
+		PROFILING_START("load factory image");
+#if defined(CFG_NAND_BOOT)
+		snprintf(cmdline_tmpbuf, CMDLINE_TMP_CONCAT_SIZE, "%s%x%s%x",
+			 NAND_MANF_CMDLINE, nand_flash_man_code, NAND_DEV_CMDLINE, nand_flash_dev_id);
+		cmdline_append(cmdline_tmpbuf);
+#endif
+		ret = load_vfy_boot(BOOTIMG_TYPE_BOOT, CFG_BOOTIMG_LOAD_ADDR);
+		ret = (int)handle_vboot_state(BOOTIMG_TYPE_BOOT);
+		if (ret != STATUS_OK)
+			mtk_arch_reset(1);
+
+		PAL_ASSERT(ret >= 0);
+
+		PROFILING_END();
+		break;
+
+	case FASTBOOT:
+	case DOWNLOAD_BOOT:
+	case UNKNOWN_BOOT:
+		break;
+
+	}
+	kernel_target_addr = get_kernel_target_addr();
+	tags_target_addr = get_tags_addr();
+
+	PAL_ASSERT(kernel_target_addr != 0);
+
+#ifdef MTK_RECOVERY_RAMDISK_SPLIT
+	if (g_boot_mode == RECOVERY_BOOT) {
+		uint32_t ramdisk_compressed_sz;
+		load_vfy_ramdisk(&ramdisk_compressed_sz);
+		ramdisk_real_sz = ramdisk_compressed_sz;
+	}
+	else
+#endif /* MTK_RECOVERY_RAMDISK_SPLIT */
+{
+	relocate_ramdisk(&ramdisk_target_addr, &ramdisk_real_sz);
+}
+	/*
+	 * merge dtb's bootargs with customized cmdline
+	 * as early as possible
+	 */
+	bootargs_init((void *)tags_target_addr);
+
+	custom_port_in_kernel(g_boot_mode, cmdline_get());
+
+#ifdef SELINUX_STATUS
+#if SELINUX_STATUS == 1
+	cmdline_append("androidboot.selinux=disabled");
+#elif SELINUX_STATUS == 2
+	cmdline_append("androidboot.selinux=permissive");
+#endif
+#endif
+
+	/* This is patch for Android Test Mode(ATM). */
+	/* 1. Sets kernel cmdline for ATM only in normal mode
+	* 2. Bypass write protect in boot mode "normal" when ATM is enabled.
+	* Background:
+	* "proinfo" partition is write protected in boot mode "normal". When ATM is enabled,
+	* we bypass write protection since we needs to write to proinfo. Whether device is in ATM
+	* should also be passed to kernel through cmdline, only seen in normal mode
+	*/
+	if (g_boot_mode == NORMAL_BOOT) {
+		if (true == get_atm_enable_status()) {
+			cmdline_append("androidboot.atm=enable");
+		} else if (false == get_atm_enable_status()) {
+			write_protect_flow();
+			cmdline_append("androidboot.atm=disabled");
+		}
+	}
+
+	// MTK read printk ratelimit config
+	read_ratelimit_config();
+#if !defined(SYSTEM_AS_ROOT) && defined(RECOVERY_AS_BOOT)
+	 /*
+	  * In Q, if RECOVERY_AS_BOOT is enabled, normal boot and recovery
+	  * ramdisk is in the same boot partition.
+	  * Recovery ramdisk is in root folder and normal boot ramdisk in another subfolder.
+	  * If MTK_RECOVERY_RAMDISK_SPLIT is enabled, we do not indicate init process to
+	  * switch root to /first_stage_mount since RECOVERY_AS_BOOT only
+	  * enabled in A/B system.
+	  */
+#if !defined(MTK_RECOVERY_RAMDISK_SPLIT)
+	if (g_boot_mode != RECOVERY_BOOT)
+		cmdline_append("androidboot.force_normal_boot=1");
+#endif
+#endif
+
+	/* pass the meta_log_disable to user space logger, default is enable */
+	if (is_meta_log_disable && (is_meta_log_disable() == 1)) {
+		cmdline_append("androidboot.meta_log_disable=1");
+	} else {
+		cmdline_append("androidboot.meta_log_disable=0");
+	}
+
+	/* pass related root of trust info via SMC call */
+	send_root_of_trust_info();
+	set_boot_phase(BOOT_PHASE_KERNEL);
+
+	boot_linux((void *)kernel_target_addr,
+			(unsigned *)tags_target_addr,
+		   	board_machtype(),
+			(void *)ramdisk_target_addr,
+			ramdisk_real_sz);
+
+	return 0;
+}
+
+#if defined(CONFIG_MTK_USB_UNIQUE_SERIAL) || (defined(MTK_SECURITY_SW_SUPPORT) && defined(MTK_SEC_FASTBOOT_UNLOCK_SUPPORT))
+static char udc_chr[32] = {"ABCDEFGHIJKLMNOPQRSTUVWXYZ456789"};
+
+int get_serial(u64 hwkey, u32 chipid, char ser[SERIALNO_LEN])
+{
+	u16 hashkey[4];
+	u32 idx, ser_idx;
+	u32 digit, id;
+	u64 tmp = hwkey;
+
+	memset(ser, 0x00, SERIALNO_LEN);
+
+	/* split to 4 key with 16-bit width each */
+	tmp = hwkey;
+	for (idx = 0; idx < ARRAY_SIZE(hashkey); idx++) {
+		hashkey[idx] = (u16)(tmp & 0xffff);
+		tmp >>= 16;
+	}
+
+	/* hash the key with chip id */
+	id = chipid;
+	for (idx = 0; idx < ARRAY_SIZE(hashkey); idx++) {
+		digit = (id % 10);
+		hashkey[idx] = (hashkey[idx] >> digit) | (hashkey[idx] << (16 - digit));
+		id = (id / 10);
+	}
+
+	/* generate serail using hashkey */
+	ser_idx = 0;
+	for (idx = 0; idx < ARRAY_SIZE(hashkey); idx++) {
+		ser[ser_idx++] = (hashkey[idx] & 0x001f);
+		ser[ser_idx++] = (hashkey[idx] & 0x00f8) >> 3;
+		ser[ser_idx++] = (hashkey[idx] & 0x1f00) >> 8;
+		ser[ser_idx++] = (hashkey[idx] & 0xf800) >> 11;
+	}
+	for (idx = 0; idx < ser_idx; idx++)
+		ser[idx] = udc_chr[(int)ser[idx]];
+	ser[ser_idx] = 0x00;
+	return 0;
+}
+#endif /* CONFIG_MTK_USB_UNIQUE_SERIAL */
+
+#ifdef SERIAL_NUM_FROM_BARCODE
+static inline int read_product_info(char *buf)
+{	
+	#define PROINFO_OFFSET 116 // barcode:64 + imei:40 + bt:6 + wifi:6
+	#define BLK_SIZE  512
+    int tmp = 0;
+    char * buf_blk = (char *)0;
+
+    if (!buf) return 0;
+
+    buf_blk = malloc(BLK_SIZE);
+    if (!buf_blk)
+    {
+        dprintf(CRITICAL, "[error] alloc proinfo buffer fail.\n");
+        return 0;
+    }
+    memset(buf_blk, 0, BLK_SIZE);
+
+    dprintf(CRITICAL, "begin read proinfo\n");
+    tmp = mboot_recovery_load_raw_part("proinfo", buf_blk, BLK_SIZE);
+    if (tmp != BLK_SIZE)
+    {
+        dprintf(CRITICAL, "[error] read proinfo fail, only read size %d, block size %d.\n", tmp, BLK_SIZE);
+        free(buf_blk);
+        return 0;
+    }
+    memcpy(buf, buf_blk + PROINFO_OFFSET, SN_BUF_LEN);
+    buf[SN_BUF_LEN] = '\0';
+    dprintf(CRITICAL, "get serialno from proinfo: \"%s\"\n", buf);
+    free(buf_blk);
+
+    for (tmp = 0; tmp < SN_BUF_LEN; tmp++) {
+        if ( (buf[tmp] == 0 || buf[tmp] == 0x20) && tmp > 0) {
+            break;
+        } else if ( !isalpha(buf[tmp]) && !isdigit(buf[tmp]))
+            return 0;
+    }
+    return tmp;
+}
+#endif
+
+#ifdef CONFIG_MTK_USB_UNIQUE_SERIAL
+static inline int read_product_usbid(char *serialno)
+{
+	u64 key;
+	u32 hrid_size, ser_len;
+	u32 i, chip_code, errcode = 0;
+	char *cur_serialp = serialno;
+	char serial_num[SERIALNO_LEN];
+
+	/* read machine type */
+	chip_code = board_machtype();
+
+	/* read hrid */
+	hrid_size = get_hrid_size();
+
+	/* check ser_buf len. if need 128bit id, should defined into cust_usb.h */
+	if (SN_BUF_LEN  < hrid_size * 8) {
+		hrid_size = 2;
+		errcode = 1;
+	}
+
+	for (i = 0; i < hrid_size / 2; i++) {
+		key = get_devinfo_with_index(13 + i * 2); /* 13, 15 */
+		key = (key << 32) | (unsigned int)get_devinfo_with_index(
+			      12 + i * 2); /* 12, 14 */
+
+		if (key != 0) {
+			get_serial(key, chip_code, serial_num);
+			ser_len = strlen(serial_num);
+		} else {
+			ser_len = strlen(DEFAULT_SERIAL_NUM);
+			memcpy(serial_num, DEFAULT_SERIAL_NUM, ser_len);
+			errcode = 2;
+		}
+		/* copy serial from serial_num to sn_buf */
+		memcpy(cur_serialp, serial_num, ser_len);
+		cur_serialp += ser_len;
+	}
+	cur_serialp = '\0';
+
+	return errcode;
+}
+#endif
+
+/******************************************************************************
+******************************************************************************/
+static void set_serial_num(void)
+{
+	unsigned int len;
+	char *id_tmp = get_env("MTK_DEVICE_ID");
+	if (!id_tmp) {
+		pal_log_info("Set serial # to default value.\n");
+		len = strlen(DEFAULT_SERIAL_NUM);
+		len = (len < SN_BUF_LEN) ? len : SN_BUF_LEN;
+		strncpy(sn_buf, DEFAULT_SERIAL_NUM, len);
+		sn_buf[len] = '\0';
+	} else {
+		pal_log_info("Set serial # from para.\n");
+		len = strlen(id_tmp);
+		len = (len < SN_BUF_LEN) ? len : SN_BUF_LEN;
+		strncpy(sn_buf, id_tmp, len);
+		sn_buf[len] = '\0';
+	}
+
+#ifdef CONFIG_MTK_USB_UNIQUE_SERIAL
+	int errcode = read_product_usbid(sn_buf);
+	if (errcode)
+		pal_log_err("Set serial # from efuse. error: %d\n", errcode);
+	len = strlen(sn_buf);
+	len = (len < SN_BUF_LEN) ? len : SN_BUF_LEN;
+	sn_buf[len] = '\0';
+#endif  // CONFIG_MTK_USB_UNIQUE_SERIAL
+
+#ifdef SERIAL_NUM_FROM_BARCODE
+	len = (unsigned int)read_product_info(sn_buf);  // sn_buf[] may be changed.
+	if (len == 0) {
+		len = strlen(DEFAULT_SERIAL_NUM);
+		len = (len < SN_BUF_LEN) ? len : SN_BUF_LEN;
+		strncpy(sn_buf, DEFAULT_SERIAL_NUM, len);
+	} else
+		len = (len < SN_BUF_LEN) ? len : SN_BUF_LEN;
+	sn_buf[len] = '\0';
+#endif  // SERIAL_NUM_FROM_BARCODE
+
+	//pal_log_err("Serial #: \"%s\"\n", sn_buf);
+	surf_udc_device.serialno = sn_buf;
+}
+
+void mt_boot_init(const struct app_descriptor *app)
+{
+	unsigned usb_init = 0;
+	unsigned sz = 0;
+
+	set_serial_num();
+
+#ifdef MTK_DEBUG_SHELL
+    if (app != NULL)
+	goto lk_debug;
+#endif
+
+	if (g_boot_mode == FASTBOOT)
+		goto fastboot;
+
+#ifdef MTK_SECURITY_SW_SUPPORT
+#if MTK_FORCE_VERIFIED_BOOT_SIG_VFY
+	/* verify oem image with android verified boot signature instead of mediatek proprietary signature */
+	/* verification is postponed to boot image loading stage */
+	/* note in this case, boot/recovery image will be verified even when secure boot is disabled */
+	g_boot_state = BOOT_STATE_RED;
+#else
+	if (0 != sec_boot_check(0))
+		g_boot_state = BOOT_STATE_RED;
+#endif
+#endif
+
+	/* Will not return */
+	boot_linux_from_storage();
+
+fastboot:
+	target_fastboot_init();
+	if (!usb_init)
+		udc_init(&surf_udc_device);
+
+	mt_part_dump();
+	sz = target_get_max_flash_size();
+	fastboot_init(target_get_scratch_address(), sz);
+	udc_start();
+
+#ifdef MTK_DEBUG_SHELL
+lk_debug:
+	   mtk_wdt_disable();
+	   dprintf(INFO, "mt_boot_init not go to kernel and disable wdt !!\n");
+#endif
+
+}
+
+APP_START(mt_boot)
+.init = mt_boot_init,
+ APP_END

+ 72 - 0
app/mt_boot/mt_boot.h

@@ -0,0 +1,72 @@
+/* Copyright Statement:
+*
+* This software/firmware and related documentation ("MediaTek Software") are
+* protected under relevant copyright laws. The information contained herein
+* is confidential and proprietary to MediaTek Inc. and/or its licensors.
+* Without the prior written permission of MediaTek inc. and/or its licensors,
+* any reproduction, modification, use or disclosure of MediaTek Software,
+* and information contained herein, in whole or in part, shall be strictly prohibited.
+*/
+/* MediaTek Inc. (C) 2017. All rights reserved.
+*
+* BY OPENING THIS FILE, RECEIVER HEREBY UNEQUIVOCALLY ACKNOWLEDGES AND AGREES
+* THAT THE SOFTWARE/FIRMWARE AND ITS DOCUMENTATIONS ("MEDIATEK SOFTWARE")
+* RECEIVED FROM MEDIATEK AND/OR ITS REPRESENTATIVES ARE PROVIDED TO RECEIVER ON
+* AN "AS-IS" BASIS ONLY. MEDIATEK EXPRESSLY DISCLAIMS ANY AND ALL WARRANTIES,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED WARRANTIES OF
+* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE OR NONINFRINGEMENT.
+* NEITHER DOES MEDIATEK PROVIDE ANY WARRANTY WHATSOEVER WITH RESPECT TO THE
+* SOFTWARE OF ANY THIRD PARTY WHICH MAY BE USED BY, INCORPORATED IN, OR
+* SUPPLIED WITH THE MEDIATEK SOFTWARE, AND RECEIVER AGREES TO LOOK ONLY TO SUCH
+* THIRD PARTY FOR ANY WARRANTY CLAIM RELATING THERETO. RECEIVER EXPRESSLY ACKNOWLEDGES
+* THAT IT IS RECEIVER'S SOLE RESPONSIBILITY TO OBTAIN FROM ANY THIRD PARTY ALL PROPER LICENSES
+* CONTAINED IN MEDIATEK SOFTWARE. MEDIATEK SHALL ALSO NOT BE RESPONSIBLE FOR ANY MEDIATEK
+* SOFTWARE RELEASES MADE TO RECEIVER'S SPECIFICATION OR TO CONFORM TO A PARTICULAR
+* STANDARD OR OPEN FORUM. RECEIVER'S SOLE AND EXCLUSIVE REMEDY AND MEDIATEK'S ENTIRE AND
+* CUMULATIVE LIABILITY WITH RESPECT TO THE MEDIATEK SOFTWARE RELEASED HEREUNDER WILL BE,
+* AT MEDIATEK'S OPTION, TO REVISE OR REPLACE THE MEDIATEK SOFTWARE AT ISSUE,
+* OR REFUND ANY SOFTWARE LICENSE FEES OR SERVICE CHARGE PAID BY RECEIVER TO
+* MEDIATEK FOR SUCH MEDIATEK SOFTWARE AT ISSUE.
+*/
+
+#ifndef _MT_BOOT_H_
+#define _MT_BOOT_H_
+
+#include "memory_layout.h"
+#include <fdt_op.h>
+#include <bootimg.h>
+
+#define DTB_MAX_SIZE    (512*1024)
+
+#ifndef DUMMY_MEMORY_LAYOUT
+
+#if DTB_MAX_SIZE > LK_DT_MAX_SIZE
+#error DTB_MAX_SIZE > LK_DT_MAX_SIZE
+#endif
+
+#if (MEMBASE != LK_LK_BASE)||(MEMSIZE > LK_LK_MAX_SIZE)
+#error check LK MEMBASE or MEMSIZE
+#endif
+
+#if (SCRATCH_ADDR != LK_DL_BASE)||(SCRATCH_SIZE > LK_DL_MAX_SIZE)
+#error check SCRATCH_ADDR or SCRATCH_SIZE
+#endif
+
+#endif
+#define EXTRACT_UBYTE(x, n)     ((uint32_t)((uint8_t *)&x)[n])
+
+void Debug_log_EMI_MPU(void) __attribute__((weak));
+
+#ifdef MTK_AB_OTA_UPDATER
+void get_AB_OTA_name(char *part_name, int size);
+#endif /* MTK_AB_OTA_UPDATER */
+
+bool get_atm_enable_status(void);
+bool cmdline_append(const char *append_string);
+void mboot_allocate_bootimg_from_mblock(struct bootimg_hdr *p_boot_hdr);
+int bldr_load_dtb(char* boot_load_partition);
+void msg_header_error(char *img_name);
+void msg_img_error(char *img_name);
+void get_AB_OTA_param(void);
+#endif  // _MT_BOOT_H_
+

+ 82 - 0
app/mt_boot/mt_hvc_call.c

@@ -0,0 +1,82 @@
+/* Copyright Statement:
+*
+* This software/firmware and related documentation ("MediaTek Software") are
+* protected under relevant copyright laws. The information contained herein
+* is confidential and proprietary to MediaTek Inc. and/or its licensors.
+* Without the prior written permission of MediaTek inc. and/or its licensors,
+* any reproduction, modification, use or disclosure of MediaTek Software,
+* and information contained herein, in whole or in part, shall be strictly prohibited.
+*/
+/* MediaTek Inc. (C) 2017. All rights reserved.
+*
+* BY OPENING THIS FILE, RECEIVER HEREBY UNEQUIVOCALLY ACKNOWLEDGES AND AGREES
+* THAT THE SOFTWARE/FIRMWARE AND ITS DOCUMENTATIONS ("MEDIATEK SOFTWARE")
+* RECEIVED FROM MEDIATEK AND/OR ITS REPRESENTATIVES ARE PROVIDED TO RECEIVER ON
+* AN "AS-IS" BASIS ONLY. MEDIATEK EXPRESSLY DISCLAIMS ANY AND ALL WARRANTIES,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED WARRANTIES OF
+* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE OR NONINFRINGEMENT.
+* NEITHER DOES MEDIATEK PROVIDE ANY WARRANTY WHATSOEVER WITH RESPECT TO THE
+* SOFTWARE OF ANY THIRD PARTY WHICH MAY BE USED BY, INCORPORATED IN, OR
+* SUPPLIED WITH THE MEDIATEK SOFTWARE, AND RECEIVER AGREES TO LOOK ONLY TO SUCH
+* THIRD PARTY FOR ANY WARRANTY CLAIM RELATING THERETO. RECEIVER EXPRESSLY ACKNOWLEDGES
+* THAT IT IS RECEIVER'S SOLE RESPONSIBILITY TO OBTAIN FROM ANY THIRD PARTY ALL PROPER LICENSES
+* CONTAINED IN MEDIATEK SOFTWARE. MEDIATEK SHALL ALSO NOT BE RESPONSIBLE FOR ANY MEDIATEK
+* SOFTWARE RELEASES MADE TO RECEIVER'S SPECIFICATION OR TO CONFORM TO A PARTICULAR
+* STANDARD OR OPEN FORUM. RECEIVER'S SOLE AND EXCLUSIVE REMEDY AND MEDIATEK'S ENTIRE AND
+* CUMULATIVE LIABILITY WITH RESPECT TO THE MEDIATEK SOFTWARE RELEASED HEREUNDER WILL BE,
+* AT MEDIATEK'S OPTION, TO REVISE OR REPLACE THE MEDIATEK SOFTWARE AT ISSUE,
+* OR REFUND ANY SOFTWARE LICENSE FEES OR SERVICE CHARGE PAID BY RECEIVER TO
+* MEDIATEK FOR SUCH MEDIATEK SOFTWARE AT ISSUE.
+*
+* The following software/firmware and/or related documentation ("MediaTek Software")
+* have been modified by MediaTek Inc. All revisions are subject to any receiver\'s
+* applicable license agreements with MediaTek Inc.
+*/
+#include <sys/types.h>
+#define LOCAL_REG_SET_DECLARE \
+	register size_t reg0 __asm__("r0") = function_id; \
+	register size_t reg1 __asm__("r1") = arg0; \
+	register size_t reg2 __asm__("r2") = arg1; \
+	register size_t reg3 __asm__("r3") = arg2; \
+	register size_t reg4 __asm__("r4") = arg3; \
+	size_t ret
+
+#define __stringify_1(x...)	#x
+#define __stringify(x...)	__stringify_1(x)
+#define ___asm_opcode_identity16(x) ((x) & 0xFFFF)
+
+#define ___asm_opcode_thumb32_first(x) (___asm_opcode_identity16((x) >> 16))
+#define ___asm_opcode_thumb32_second(x) (___asm_opcode_identity16(x))
+#define ___asm_opcode_to_mem_thumb16(x) ___asm_opcode_identity16(x)
+
+
+#define ___inst_thumb32(first, second) \
+	".short " __stringify(first) ", " __stringify(second) "\n"
+
+#define __inst_thumb32(x) ___inst_thumb32(				\
+	___asm_opcode_to_mem_thumb16(___asm_opcode_thumb32_first(x)),	\
+	___asm_opcode_to_mem_thumb16(___asm_opcode_thumb32_second(x))	\
+)
+#define __HVC(imm16) __inst_thumb32(0xF7E08000 | (((imm16) & 0xF000) << 4) | ((imm16) & 0x0FFF))
+
+size_t mt_hvc_call(size_t function_id,
+	size_t arg0, size_t arg1, size_t arg2,
+	size_t arg3, size_t *r1, size_t *r2, size_t *r3)
+{
+	LOCAL_REG_SET_DECLARE;
+#ifdef SUPPORT_ARMV7VE
+	__asm__ volatile ("hvc #0x0\n" : "+r"(reg0),
+		"+r"(reg1), "+r"(reg2), "+r"(reg3), "+r"(reg4));
+#else
+	__asm__ volatile (__HVC(0) : "+r"(reg0),
+		"+r"(reg1), "+r"(reg2), "+r"(reg3), "+r"(reg4));
+#endif
+	ret = reg0;
+	if (r1 != NULL)
+		*r1 = reg1;
+	if (r2 != NULL)
+		*r2 = reg2;
+	if (r3 != NULL)
+		*r3 = reg3;
+	return ret;
+}

+ 42 - 0
app/mt_boot/mt_hvc_call.h

@@ -0,0 +1,42 @@
+/* Copyright Statement:
+*
+* This software/firmware and related documentation ("MediaTek Software") are
+* protected under relevant copyright laws. The information contained herein
+* is confidential and proprietary to MediaTek Inc. and/or its licensors.
+* Without the prior written permission of MediaTek inc. and/or its licensors,
+* any reproduction, modification, use or disclosure of MediaTek Software,
+* and information contained herein, in whole or in part, shall be strictly prohibited.
+*/
+/* MediaTek Inc. (C) 2017. All rights reserved.
+*
+* BY OPENING THIS FILE, RECEIVER HEREBY UNEQUIVOCALLY ACKNOWLEDGES AND AGREES
+* THAT THE SOFTWARE/FIRMWARE AND ITS DOCUMENTATIONS ("MEDIATEK SOFTWARE")
+* RECEIVED FROM MEDIATEK AND/OR ITS REPRESENTATIVES ARE PROVIDED TO RECEIVER ON
+* AN "AS-IS" BASIS ONLY. MEDIATEK EXPRESSLY DISCLAIMS ANY AND ALL WARRANTIES,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED WARRANTIES OF
+* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE OR NONINFRINGEMENT.
+* NEITHER DOES MEDIATEK PROVIDE ANY WARRANTY WHATSOEVER WITH RESPECT TO THE
+* SOFTWARE OF ANY THIRD PARTY WHICH MAY BE USED BY, INCORPORATED IN, OR
+* SUPPLIED WITH THE MEDIATEK SOFTWARE, AND RECEIVER AGREES TO LOOK ONLY TO SUCH
+* THIRD PARTY FOR ANY WARRANTY CLAIM RELATING THERETO. RECEIVER EXPRESSLY ACKNOWLEDGES
+* THAT IT IS RECEIVER'S SOLE RESPONSIBILITY TO OBTAIN FROM ANY THIRD PARTY ALL PROPER LICENSES
+* CONTAINED IN MEDIATEK SOFTWARE. MEDIATEK SHALL ALSO NOT BE RESPONSIBLE FOR ANY MEDIATEK
+* SOFTWARE RELEASES MADE TO RECEIVER'S SPECIFICATION OR TO CONFORM TO A PARTICULAR
+* STANDARD OR OPEN FORUM. RECEIVER'S SOLE AND EXCLUSIVE REMEDY AND MEDIATEK'S ENTIRE AND
+* CUMULATIVE LIABILITY WITH RESPECT TO THE MEDIATEK SOFTWARE RELEASED HEREUNDER WILL BE,
+* AT MEDIATEK'S OPTION, TO REVISE OR REPLACE THE MEDIATEK SOFTWARE AT ISSUE,
+* OR REFUND ANY SOFTWARE LICENSE FEES OR SERVICE CHARGE PAID BY RECEIVER TO
+* MEDIATEK FOR SUCH MEDIATEK SOFTWARE AT ISSUE.
+*
+* The following software/firmware and/or related documentation ("MediaTek Software")
+* have been modified by MediaTek Inc. All revisions are subject to any receiver\'s
+* applicable license agreements with MediaTek Inc.
+*/
+
+#ifndef _MT_HVC_CALL_H_
+#define _MT_HVC_CALL_H_
+
+size_t mt_hvc_call(size_t function_id,
+	size_t arg0, size_t arg1, size_t arg2,
+	size_t arg3, size_t *r1, size_t *r2, size_t *r3);
+#endif				/* _MT_HVC_CALL_H_ */

+ 116 - 0
app/mt_boot/mt_secure_call.c

@@ -0,0 +1,116 @@
+/* Copyright Statement:
+*
+* This software/firmware and related documentation ("MediaTek Software") are
+* protected under relevant copyright laws. The information contained herein
+* is confidential and proprietary to MediaTek Inc. and/or its licensors.
+* Without the prior written permission of MediaTek inc. and/or its licensors,
+* any reproduction, modification, use or disclosure of MediaTek Software,
+* and information contained herein, in whole or in part, shall be strictly prohibited.
+*/
+/* MediaTek Inc. (C) 2017. All rights reserved.
+*
+* BY OPENING THIS FILE, RECEIVER HEREBY UNEQUIVOCALLY ACKNOWLEDGES AND AGREES
+* THAT THE SOFTWARE/FIRMWARE AND ITS DOCUMENTATIONS ("MEDIATEK SOFTWARE")
+* RECEIVED FROM MEDIATEK AND/OR ITS REPRESENTATIVES ARE PROVIDED TO RECEIVER ON
+* AN "AS-IS" BASIS ONLY. MEDIATEK EXPRESSLY DISCLAIMS ANY AND ALL WARRANTIES,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED WARRANTIES OF
+* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE OR NONINFRINGEMENT.
+* NEITHER DOES MEDIATEK PROVIDE ANY WARRANTY WHATSOEVER WITH RESPECT TO THE
+* SOFTWARE OF ANY THIRD PARTY WHICH MAY BE USED BY, INCORPORATED IN, OR
+* SUPPLIED WITH THE MEDIATEK SOFTWARE, AND RECEIVER AGREES TO LOOK ONLY TO SUCH
+* THIRD PARTY FOR ANY WARRANTY CLAIM RELATING THERETO. RECEIVER EXPRESSLY ACKNOWLEDGES
+* THAT IT IS RECEIVER'S SOLE RESPONSIBILITY TO OBTAIN FROM ANY THIRD PARTY ALL PROPER LICENSES
+* CONTAINED IN MEDIATEK SOFTWARE. MEDIATEK SHALL ALSO NOT BE RESPONSIBLE FOR ANY MEDIATEK
+* SOFTWARE RELEASES MADE TO RECEIVER'S SPECIFICATION OR TO CONFORM TO A PARTICULAR
+* STANDARD OR OPEN FORUM. RECEIVER'S SOLE AND EXCLUSIVE REMEDY AND MEDIATEK'S ENTIRE AND
+* CUMULATIVE LIABILITY WITH RESPECT TO THE MEDIATEK SOFTWARE RELEASED HEREUNDER WILL BE,
+* AT MEDIATEK'S OPTION, TO REVISE OR REPLACE THE MEDIATEK SOFTWARE AT ISSUE,
+* OR REFUND ANY SOFTWARE LICENSE FEES OR SERVICE CHARGE PAID BY RECEIVER TO
+* MEDIATEK FOR SUCH MEDIATEK SOFTWARE AT ISSUE.
+*
+* The following software/firmware and/or related documentation ("MediaTek Software")
+* have been modified by MediaTek Inc. All revisions are subject to any receiver\'s
+* applicable license agreements with MediaTek Inc.
+*/
+#include <sys/types.h>
+#include "mtk_secure_api.h"
+#define LOCAL_REG_SET_DECLARE \
+	register size_t reg0 __asm__("r0") = function_id; \
+	register size_t reg1 __asm__("r1") = arg0; \
+	register size_t reg2 __asm__("r2") = arg1; \
+	register size_t reg3 __asm__("r3") = arg2; \
+	register size_t reg4 __asm__("r4") = arg3; \
+	size_t ret
+
+size_t mt_secure_call_all(size_t function_id,
+	size_t arg0, size_t arg1, size_t arg2,
+	size_t arg3, size_t *r1, size_t *r2, size_t *r3)
+{
+	LOCAL_REG_SET_DECLARE;
+
+	__asm__ volatile ("smc #0x0\n" : "+r"(reg0),
+		"+r"(reg1), "+r"(reg2), "+r"(reg3), "+r"(reg4));
+	ret = reg0;
+	if (r1 != NULL)
+		*r1 = reg1;
+	if (r2 != NULL)
+		*r2 = reg2;
+	if (r3 != NULL)
+		*r3 = reg3;
+	return ret;
+}
+
+void jumparch64_smc(size_t addr, size_t arg1, size_t arg2, size_t arg3)
+{
+	mt_secure_call(MTK_SIP_KERNEL_BOOT, addr, arg1, arg2, arg3);
+}
+
+unsigned int get_rnd(unsigned int *rnd)
+{
+	return mt_secure_call_all(MTK_SIP_LK_GET_RND, 0, 0, 0, 0, (size_t *) rnd, 0, 0);
+}
+
+unsigned int md_reg_write_smc(size_t arg0, size_t arg1, size_t arg2, size_t arg3)
+{
+	return mt_secure_call(MTK_SIP_LK_MD_REG_WRITE, arg0, arg1, arg2, arg3);
+}
+
+unsigned int crypto_hw_init(unsigned int share_mem_addr, unsigned int share_mem_len)
+{
+	return mt_secure_call(MTK_SIP_LK_CRYPTO_HW_ENGINE_INIT, share_mem_addr, share_mem_len, 0, 0);
+}
+
+unsigned int crypto_hw_disable(void)
+{
+	return mt_secure_call(MTK_SIP_LK_CRYPTO_HW_ENGINE_DISABLE, 0, 0, 0, 0);
+}
+
+unsigned int sha256atf_init(void)
+{
+	return mt_secure_call(MTK_SIP_LK_CRYPTO_SHA256_INIT, 0, 0, 0, 0);
+}
+
+unsigned int sha256atf_process(const unsigned char *in, unsigned long len)
+{
+	return mt_secure_call(MTK_SIP_LK_CRYPTO_SHA256_PROCESS, (size_t)in, len, 0, 0);
+}
+
+unsigned int sha256atf_done(void)
+{
+	return mt_secure_call(MTK_SIP_LK_CRYPTO_SHA256_DONE, 0, 0, 0, 0);
+}
+
+int32_t rpmb_init(void)
+{
+	return mt_secure_call(MTK_SIP_LK_RPMB_INIT, 0, 0, 0, 0);
+}
+
+int32_t rpmb_uninit(void)
+{
+	return mt_secure_call(MTK_SIP_LK_RPMB_UNINIT, 0, 0, 0, 0);
+}
+
+int32_t rpmb_hmac(uint32_t pattern, uint32_t size)
+{
+	return mt_secure_call(MTK_SIP_LK_RPMB_HMAC, pattern, size, 0, 0);
+}

+ 76 - 0
app/mt_boot/mtk_secure_api.h

@@ -0,0 +1,76 @@
+/* Copyright Statement:
+*
+* This software/firmware and related documentation ("MediaTek Software") are
+* protected under relevant copyright laws. The information contained herein
+* is confidential and proprietary to MediaTek Inc. and/or its licensors.
+* Without the prior written permission of MediaTek inc. and/or its licensors,
+* any reproduction, modification, use or disclosure of MediaTek Software,
+* and information contained herein, in whole or in part, shall be strictly prohibited.
+*/
+/* MediaTek Inc. (C) 2017. All rights reserved.
+*
+* BY OPENING THIS FILE, RECEIVER HEREBY UNEQUIVOCALLY ACKNOWLEDGES AND AGREES
+* THAT THE SOFTWARE/FIRMWARE AND ITS DOCUMENTATIONS ("MEDIATEK SOFTWARE")
+* RECEIVED FROM MEDIATEK AND/OR ITS REPRESENTATIVES ARE PROVIDED TO RECEIVER ON
+* AN "AS-IS" BASIS ONLY. MEDIATEK EXPRESSLY DISCLAIMS ANY AND ALL WARRANTIES,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED WARRANTIES OF
+* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE OR NONINFRINGEMENT.
+* NEITHER DOES MEDIATEK PROVIDE ANY WARRANTY WHATSOEVER WITH RESPECT TO THE
+* SOFTWARE OF ANY THIRD PARTY WHICH MAY BE USED BY, INCORPORATED IN, OR
+* SUPPLIED WITH THE MEDIATEK SOFTWARE, AND RECEIVER AGREES TO LOOK ONLY TO SUCH
+* THIRD PARTY FOR ANY WARRANTY CLAIM RELATING THERETO. RECEIVER EXPRESSLY ACKNOWLEDGES
+* THAT IT IS RECEIVER'S SOLE RESPONSIBILITY TO OBTAIN FROM ANY THIRD PARTY ALL PROPER LICENSES
+* CONTAINED IN MEDIATEK SOFTWARE. MEDIATEK SHALL ALSO NOT BE RESPONSIBLE FOR ANY MEDIATEK
+* SOFTWARE RELEASES MADE TO RECEIVER'S SPECIFICATION OR TO CONFORM TO A PARTICULAR
+* STANDARD OR OPEN FORUM. RECEIVER'S SOLE AND EXCLUSIVE REMEDY AND MEDIATEK'S ENTIRE AND
+* CUMULATIVE LIABILITY WITH RESPECT TO THE MEDIATEK SOFTWARE RELEASED HEREUNDER WILL BE,
+* AT MEDIATEK'S OPTION, TO REVISE OR REPLACE THE MEDIATEK SOFTWARE AT ISSUE,
+* OR REFUND ANY SOFTWARE LICENSE FEES OR SERVICE CHARGE PAID BY RECEIVER TO
+* MEDIATEK FOR SUCH MEDIATEK SOFTWARE AT ISSUE.
+*
+* The following software/firmware and/or related documentation ("MediaTek Software")
+* have been modified by MediaTek Inc. All revisions are subject to any receiver\'s
+* applicable license agreements with MediaTek Inc.
+*/
+
+#ifndef _MTK_SECURE_API_H_
+#define _MTK_SECURE_API_H_
+
+#include <plat_smc_id_table.h>
+
+/* Error Code */
+#define SIP_SVC_E_SUCCESS               0
+#define SIP_SVC_E_NOT_SUPPORTED         -1
+#define SIP_SVC_E_INVALID_PARAMS        -2
+#define SIP_SVC_E_INVALID_Range         -3
+#define SIP_SVC_E_PERMISSION_DENY       -4
+
+size_t mt_secure_call_all(size_t function_id,
+	size_t arg0, size_t arg1, size_t arg2,
+	size_t arg3, size_t *r1, size_t *r2, size_t *r3);
+
+#define mt_secure_call(_fun_id, _arg0, _arg1, _arg2, _arg3) \
+	mt_secure_call_all(_fun_id, _arg0, _arg1, _arg2, _arg3, 0, 0, 0)
+#define mt_secure_call_ret1(_fun_id, _arg0, _arg1, _arg2, _arg3) \
+	mt_secure_call_all(_fun_id, _arg0, _arg1, _arg2, _arg3, 0, 0, 0)
+#define mt_secure_call_ret2(_fun_id, _arg0, _arg1, _arg2, _arg3, _r1) \
+	mt_secure_call_all(_fun_id, _arg0, _arg1, _arg2, _arg3, _r1, 0, 0)
+#define mt_secure_call_ret3(_fun_id, _arg0, _arg1, _arg2, _arg3, _r1, _r2) \
+	mt_secure_call_all(_fun_id, _arg0, _arg1, _arg2, _arg3, _r1, _r2, 0)
+#define mt_secure_call_ret4(_fun_id, _arg0,\
+	_arg1, _arg2, _arg3, _r1, _r2, _r3) \
+	mt_secure_call_all(_fun_id, _arg0, _arg1, _arg2, _arg3, _r1, _r2, _r3)
+
+void jumparch64_smc(size_t addr, size_t arg1, size_t arg2, size_t arg3);
+unsigned int get_rnd(unsigned int *rnd);
+unsigned int md_reg_write_smc(size_t arg0, size_t arg1, size_t arg2, size_t arg3);
+unsigned int crypto_hw_init(unsigned int share_mem_addr, unsigned int share_mem_len);
+unsigned int crypto_hw_disable(void);
+unsigned int sha256atf_init(void);
+unsigned int sha256atf_process(const unsigned char *in, unsigned long len);
+unsigned int sha256atf_done(void);
+int32_t rpmb_init(void);
+int32_t rpmb_uninit(void);
+int32_t rpmb_hmac(uint32_t pattern, uint32_t size);
+
+#endif				/* _MTK_SECURE_API_H_ */

+ 68 - 0
app/mt_boot/mtransfer/bulk_process.c

@@ -0,0 +1,68 @@
+#include <stdlib.h>
+#include <app.h>
+#include <debug.h>
+#include <arch/arm.h>
+#include <dev/udc.h>
+#include <string.h>
+#include <kernel/thread.h>
+#include <kernel/event.h>
+#include <arch/ops.h>
+#include <target.h>
+#include <platform.h>
+#include <platform/mt_gpt.h>
+
+#include "bulk_process.h"
+#include "transfer.h"
+#include "pal_log.h"
+
+#if (defined(MTK_UFS_SUPPORT) || defined(MTK_EMMC_SUPPORT))
+extern u64 emmc_write(u32 part_id, u64 offset, void *data, u64 size);
+
+static void write_bulk_internal(bulk_status_t* status);
+void init_bulk_process_status(bulk_status_t* status,  partition_info_struct_t* partition)
+{
+	status->partition = partition;
+	status->image_address_offset = 0;
+}
+
+void end_write_bulk(bulk_status_t* status)
+{
+}
+static void write_bulk_internal(bulk_status_t* status)
+{
+	if (emmc_write(status->partition->part_id, status->partition->base_addr+status->image_address_offset , status->buf, status->byte_to_process) != status->byte_to_process)
+	{
+		status->handle_status = STATUS_EMMC_ERR;
+	}
+
+	if (status->handle_status  != STATUS_OK)
+	{
+		pal_log_err("[BULK] S_STORAGE_WRITE_FAILED:%d, status=%d, size=%d\n",__LINE__, status->handle_status, status->byte_to_process);
+		return;
+	}
+
+	status->image_address_offset += status->byte_to_process;
+
+	status->byte_to_process = 0;
+	return ;
+}
+
+void write_bulk_data(bulk_status_t* status, uint8* data, uint32 length)
+{
+	status->buf = data;
+	status->byte_to_process = length;
+	do
+	{
+		write_bulk_internal(status);
+		if (status->handle_status != STATUS_OK)
+		{
+			return;
+		}
+
+	} while (status->byte_to_process > 0);
+
+	return;
+}
+
+#endif
+

+ 32 - 0
app/mt_boot/mtransfer/bulk_process.h

@@ -0,0 +1,32 @@
+#ifndef 	_BULK_DATA_PROCESS_H_
+#define 	_BULK_DATA_PROCESS_H_
+
+#include "transfer.h"
+
+typedef struct bulk_cache_ctx
+{
+	uint8* c_base;             //cache buffer base
+	uint32 c_offset;             //cache buffer offset
+	uint32 c_size;             //cache buffer size
+} bulk_cache_ctx_t;
+
+typedef struct bulk_status
+{
+	status_t handle_status;
+	uint32 byte_to_process;    // byte to be processed in one packet.
+	uint64 image_address_offset;
+	uint8 *buf;                        // byte buffer of one packet.
+	bulk_cache_ctx_t ctx;           //buffer download context
+	partition_info_struct_t* partition;
+} bulk_status_t;
+
+
+void init_bulk_process_status(bulk_status_t* status, partition_info_struct_t* partition);
+void write_bulk_data(bulk_status_t* status, uint8* data, uint32 length);
+
+//ex functions
+void end_write_bulk(bulk_status_t* status);
+
+
+
+#endif

+ 144 - 0
app/mt_boot/mtransfer/bulk_process_nand.c

@@ -0,0 +1,144 @@
+#include <stdlib.h>
+#include <app.h>
+#include <debug.h>
+#include <arch/arm.h>
+#include <dev/udc.h>
+#include <string.h>
+#include <kernel/thread.h>
+#include <kernel/event.h>
+#include <arch/ops.h>
+#include <target.h>
+#include <platform.h>
+#include <platform/mt_gpt.h>
+
+#include "bulk_process.h"
+#include "pal_log.h"
+
+#if (!defined(MTK_UFS_SUPPORT) && !defined(MTK_EMMC_SUPPORT))
+#define NAND_TYPE
+
+#if defined(MTK_MLC_NAND_SUPPORT) || defined(MTK_TLC_NAND_SUPPORT)
+extern int nand_write_img(u64 addr, void *data, u32 img_sz,u64 partition_size,int partition_type);
+extern int nand_write_img_ex(u64 addr, void *data, u32 length,u64 total_size, u32 *next_offset, u64 partition_start,u64 partition_size, int img_type);
+#else
+extern int nand_write_img(u32 addr, void *data, u32 img_sz,u32 partition_size,int partition_type);
+extern int nand_write_img_ex(u32 addr, void *data, u32 length,u32 total_size, u32 *next_offset, u32 partition_start,u32 partition_size, int img_type);
+#endif
+
+
+#if 0   //fake NAND.
+int nand_get_alignment()
+{
+	return 4*1024*1024;
+}
+int nand_write_img(u32 addr, void *data, u32 img_sz,u32 partition_size,int partition_type)
+{
+	return 0;
+}
+int get_nand_image_type(const char* arg)
+{
+	return 0;
+}
+#endif
+
+static void init_cache_context(bulk_status_t* status);
+static void write_bulk_internal(bulk_status_t* status, bool flush_end);
+
+
+void init_bulk_process_status(bulk_status_t* status,  partition_info_struct_t* partition)
+{
+	status->partition = partition;
+	status->image_address_offset = 0;
+	init_cache_context(status);
+}
+
+extern int nand_get_alignment();
+static void adjust_cache_size(struct bulk_cache_ctx* ctx)
+{
+	uint32 size = nand_get_alignment();
+
+	//ctx->c_base = (uint8*)memalign(128, size);
+	ctx->c_base = get_global_cache1();
+	ctx->c_size = size;
+	ctx->c_offset = 0;
+}
+
+
+static void init_cache_context(bulk_status_t* status)
+{
+	adjust_cache_size(&status->ctx);
+}
+
+void end_write_bulk(bulk_status_t* status)
+{
+	write_bulk_internal(status, true);
+}
+
+extern int get_nand_image_type(const char* arg);
+static void write_bulk_internal(bulk_status_t* status, bool flush_end)
+{
+	uint32 slot_len = status->ctx.c_size - status->ctx.c_offset;
+
+	if(slot_len <= status->byte_to_process || flush_end)
+	{
+		uint32 actural_size = 0;
+		//cache is full.
+		if(flush_end)
+		{
+			memset(status->ctx.c_base + status->ctx.c_offset, 0xFF, status->ctx.c_size - status->ctx.c_offset);
+			actural_size = status->ctx.c_offset;
+		}
+		else
+		{
+			memcpy(status->ctx.c_base + status->ctx.c_offset, status->buf, slot_len);
+			actural_size = status->ctx.c_size;
+		}
+
+		if (nand_write_img((u64)(status->partition->base_addr+status->image_address_offset), (char*)status->ctx.c_base,  status->ctx.c_size
+			,(u64)status->partition->max_size, get_nand_image_type(status->partition->name)))
+		{
+			status->handle_status = STATUS_NAND_ERR;
+			pal_log_err("[BULK] S_STORAGE_WRITE_FAILED:%d, status=%d, size=%d\n",__LINE__, status->handle_status, status->byte_to_process);
+			return;
+		}
+
+		status->buf += slot_len;
+		status->byte_to_process -= slot_len;
+		status->ctx.c_offset = 0;// reset cache.
+
+		status->image_address_offset += status->ctx.c_size;
+
+	}
+	else
+	{
+		//cache is not full.
+		memcpy(status->ctx.c_base + status->ctx.c_offset, status->buf, status->byte_to_process);
+		status->ctx.c_offset += status->byte_to_process;
+
+		status->byte_to_process = 0;
+	}
+
+	return ;
+}
+
+
+void write_bulk_data(bulk_status_t* status, uint8* data, uint32 length)
+{
+	status->buf = data;
+	status->byte_to_process = length;
+	do
+	{
+		write_bulk_internal(status, false);
+
+		if (status->handle_status != STATUS_OK)
+		{
+			return;
+		}
+
+	} while (status->byte_to_process > 0);
+
+	return;
+}
+
+#endif
+

+ 315 - 0
app/mt_boot/mtransfer/sparse_state_machine.c

@@ -0,0 +1,315 @@
+#if (defined(MTK_UFS_SUPPORT) || defined(MTK_EMMC_SUPPORT))
+#include <debug.h>
+
+#include "sparse_format.h"
+#include "sparse_state_machine.h"
+#include "pal_log.h"
+
+typedef unsigned int u32;
+typedef unsigned long long u64;
+extern u64 emmc_write(u32 part_id, u64 offset, void *data, u64 size);
+extern void * memset(void *s, int c, size_t count);
+extern void *memcpy(void *dest, const void *src, size_t count);
+
+//only engine data structure.
+static unsparse_data_t m_unsparse_data;
+
+static void write_sparse_data_internal(unsparse_status_t* status);
+
+static void set_unsparse_status( unsparse_status_t* status,
+								status_t handle_status,
+								unsparse_phase_t wait_phase,
+								uint32 size,
+								uint8 *buf	)
+{
+	status->handle_status = handle_status;
+	status->wait_phase = wait_phase;
+	status->byte_to_process = size;
+	status->buf = buf;
+}
+
+void init_unsparse_status(unsparse_status_t* status, partition_info_struct_t* partition)
+{
+	memset(status, 0, sizeof(unsparse_status_t));
+	set_unsparse_status(status, STATUS_OK, UNSPARSE_WAIT_SPARSE_HEADER, 0, 0);
+	status->partition = partition;
+}
+
+void end_write_sparse_data(unsparse_status_t* status)
+{
+	//for the last package
+}
+static void memsetint(void* p, int i, int len)
+{
+	int idx=0;
+	int count = len>>2;
+	int* buf = (int*)p;
+	while(idx < count)
+	{
+		buf[idx++] = i;
+	}
+}
+inline uint64 emmc_write_wp(uint32 part_id, uint64 offset, void *data, uint64 size)
+{
+	return emmc_write(part_id, offset, data, size);
+}
+
+static void write_sparse_data_internal(unsparse_status_t* status)
+{
+	uint32 size = status->byte_to_process;
+	uint8 *buf = status->buf;
+	uint32 sizeOfX=0;
+
+	int filled_seed = 0;
+	uint8* filled_data_cache = 0;
+	uint32 filled_data_len= 0 ;
+	if (size==0)
+	{
+		return ;
+	}
+
+	switch (status->wait_phase)
+	{
+	case UNSPARSE_WAIT_SPARSE_HEADER:
+		{
+			if (size >=sizeof (sparse_header_t))
+			{
+				memset((void*)&m_unsparse_data, 0x00, sizeof(unsparse_data_t));
+				memcpy((void*)&m_unsparse_data.sparse_hdr, buf, sizeof (sparse_header_t));
+
+				// for real sparse header larger than sparse_header_t struct
+				// for titan ext4_sparse_header_8byte_align:  sparse_header_t 8byte align, chunk_header_t 8byte align
+
+				size -= m_unsparse_data.sparse_hdr.file_hdr_sz;
+				buf+= m_unsparse_data.sparse_hdr.file_hdr_sz;
+
+				m_unsparse_data.unhandle_buf_size = 0;
+				m_unsparse_data.chunks_processed = 0;
+				set_unsparse_status(status, STATUS_OK, UNSPARSE_WAIT_CHUNK_HEADER, size, buf);
+			}
+			break;
+		}
+
+	case UNSPARSE_WAIT_CHUNK_HEADER:
+		{
+			if(m_unsparse_data.chunks_processed >= m_unsparse_data.sparse_hdr.total_chunks)
+			{
+				set_unsparse_status(status, STATUS_OK, UNSPARSE_WAIT_CHUNK_HEADER, 0, buf);
+				return;
+			}
+			if (m_unsparse_data.unhandle_buf_size + size >=( m_unsparse_data.sparse_hdr.chunk_hdr_sz))
+			{
+				if (m_unsparse_data.unhandle_buf_size > 0) {
+					uint32 sizeOfUsedBuf = m_unsparse_data.sparse_hdr.chunk_hdr_sz - m_unsparse_data.unhandle_buf_size;
+					memcpy(&m_unsparse_data.chunk_hdr, m_unsparse_data.unhandle_buf, m_unsparse_data.unhandle_buf_size);
+					// for real sparse header larger than sparse_header_t struct
+					if((m_unsparse_data.sparse_hdr.chunk_hdr_sz>sizeof(chunk_header_t)))
+					{
+						memcpy( ((uint8*)&m_unsparse_data.chunk_hdr) + m_unsparse_data.unhandle_buf_size, buf, sizeOfUsedBuf-(m_unsparse_data.sparse_hdr.chunk_hdr_sz-sizeof(chunk_header_t)));
+					}else{
+						memcpy( ((uint8*)&m_unsparse_data.chunk_hdr) + m_unsparse_data.unhandle_buf_size, buf, sizeOfUsedBuf);
+					}
+
+					size -= sizeOfUsedBuf;
+					buf+= sizeOfUsedBuf;
+					m_unsparse_data.unhandle_buf_size = 0;
+				}
+				else
+				{
+					// for real sparse header larger than sparse_header_t struct
+					memcpy(&m_unsparse_data.chunk_hdr, buf, sizeof(chunk_header_t));
+					size -= m_unsparse_data.sparse_hdr.chunk_hdr_sz;
+					buf+= m_unsparse_data.sparse_hdr.chunk_hdr_sz;
+				}
+
+				m_unsparse_data.chunk_remain_data_size = (uint64)m_unsparse_data.chunk_hdr.chunk_sz*m_unsparse_data.sparse_hdr.blk_sz;
+				switch (m_unsparse_data.chunk_hdr.chunk_type)
+				{
+				case CHUNK_TYPE_RAW:
+					{
+						set_unsparse_status(status, STATUS_OK, UNSPARSE_WAIT_CHUNK_DATA, size, buf);
+						break;
+					}
+				case CHUNK_TYPE_DONT_CARE:
+					{
+						m_unsparse_data.image_address_offset+=m_unsparse_data.chunk_remain_data_size;
+						m_unsparse_data.chunk_remain_data_size = 0;
+						set_unsparse_status(status, STATUS_OK, UNSPARSE_WAIT_CHUNK_HEADER, size, buf);
+						break;
+					}
+				case CHUNK_TYPE_FILL:
+					{
+						set_unsparse_status(status, STATUS_OK, UNSPARSE_WAIT_CHUNK_FILL, size, buf);
+						break;
+					}
+				case CHUNK_TYPE_CRC:
+					{
+						set_unsparse_status(status, STATUS_OK, UNSPARSE_WAIT_CHUNK_CRC, size, buf);
+						break;
+					}
+				default:
+					pal_log_err("@: CHUNK_TYPE_UNKNOWN: 0x%x\n", m_unsparse_data.chunk_hdr.chunk_type);
+					status->handle_status = STATUS_UNKNOWN_SPARSE_CHUNK_TYPE;
+					return;
+				}
+				++m_unsparse_data.chunks_processed;
+			}
+			else
+			{
+				m_unsparse_data.unhandle_buf_size = size;
+				memcpy(m_unsparse_data.unhandle_buf, buf, size);
+				size = 0; // force to jump out while loop
+				set_unsparse_status(status, STATUS_OK, UNSPARSE_WAIT_CHUNK_HEADER, size, buf);
+			}
+			break;
+		}
+	case UNSPARSE_WAIT_CHUNK_FILL:
+		{
+			filled_seed = *(int*)buf;
+			buf += sizeof(uint32);
+			size -= sizeof(uint32);
+
+#define FILLED_DATA_CACHE_SIZE 2*1024*1024
+			filled_data_cache = (uint8*)get_global_cache1();;
+			memsetint(filled_data_cache, filled_seed, FILLED_DATA_CACHE_SIZE);
+
+			while(true)
+			{
+				filled_data_len = (m_unsparse_data.chunk_remain_data_size > FILLED_DATA_CACHE_SIZE) ?
+FILLED_DATA_CACHE_SIZE : m_unsparse_data.chunk_remain_data_size;
+				if(filled_data_len == 0)
+				{
+					break;
+				}
+				if (emmc_write_wp(status->partition->part_id, status->partition->base_addr+m_unsparse_data.image_address_offset , filled_data_cache, filled_data_len) != filled_data_len)
+				{
+					status->handle_status = STATUS_EMMC_ERR;
+				}
+				//status->handle_status = storage_interface.write(status->image_base_addr+m_unsparse_data.image_address_offset, filled_data_cache, kk, status->arg);
+				if (status->handle_status  != STATUS_OK)
+				{
+					pal_log_err("[UNSPARSE] S_STORAGE_WRITE_FAILED:%d, status=%d, size=%d\n",__LINE__, status->handle_status, status->byte_to_process);
+					return;
+				}
+
+				m_unsparse_data.image_address_offset += filled_data_len;
+				m_unsparse_data.chunk_remain_data_size -= filled_data_len;
+			}
+
+			set_unsparse_status(status, STATUS_OK, UNSPARSE_WAIT_CHUNK_HEADER, size, buf);
+			break;
+		}
+	case UNSPARSE_WAIT_CHUNK_CRC:
+		{
+			filled_seed = *(uint32*)buf;
+			buf += sizeof(uint32);
+			size -= sizeof(uint32);
+			m_unsparse_data.chunk_remain_data_size = 0;
+			set_unsparse_status(status, STATUS_OK, UNSPARSE_WAIT_CHUNK_HEADER, size, buf);
+			break;
+		}
+	case UNSPARSE_WAIT_CHUNK_DATA:
+		{
+			if (size >= m_unsparse_data.chunk_remain_data_size)
+			{
+				if (emmc_write_wp(status->partition->part_id, status->partition->base_addr+m_unsparse_data.image_address_offset , buf,  m_unsparse_data.chunk_remain_data_size) != m_unsparse_data.chunk_remain_data_size)
+				{
+					status->handle_status = STATUS_EMMC_ERR;
+				}
+				//status->handle_status = storage_interface.write(status->image_base_addr+m_unsparse_data.image_address_offset, buf,  m_unsparse_data.chunk_remain_data_size, status->arg);
+				if (status->handle_status  != STATUS_OK)
+				{
+					pal_log_err("[UNSPARSE] S_STORAGE_WRITE_FAILED:%d, status=%d, size=%d\n",__LINE__, status->handle_status, status->byte_to_process);
+					return;
+				}
+
+				buf += m_unsparse_data.chunk_remain_data_size;
+				size -= m_unsparse_data.chunk_remain_data_size;
+				m_unsparse_data.image_address_offset += m_unsparse_data.chunk_remain_data_size;
+				m_unsparse_data.chunk_remain_data_size = 0;
+				set_unsparse_status(status, STATUS_OK, UNSPARSE_WAIT_CHUNK_HEADER, size, buf);
+			}
+			else
+			{   //big trunk, so it need more than 1 package.
+				sizeOfX = size;
+				if(size &  (STORAGE_BLOCK_SIZE-1)) //not 512 aligned.
+				{
+					if(size < STORAGE_BLOCK_SIZE) //last fragment in a package. this package must have successive package that contain the identical trunk.
+					{
+						set_unsparse_status(status, STATUS_SPARSE_INCOMPLETE, UNSPARSE_WAIT_CHUNK_DATA, size, buf);
+						break;
+					}
+					else
+					{
+						size &= ~(STORAGE_BLOCK_SIZE-1);
+					}
+				}
+
+
+				if (emmc_write_wp(status->partition->part_id, status->partition->base_addr+m_unsparse_data.image_address_offset , buf,  size) != size)
+				{
+					status->handle_status = STATUS_EMMC_ERR;
+				}
+				// status->handle_status = storage_interface.write(status->image_base_addr+m_unsparse_data.image_address_offset, buf,  size, status->arg);
+
+				if (status->handle_status  != STATUS_OK)
+				{
+					pal_log_err( "[UNSPARSE] S_STORAGE_WRITE_FAILED:%d, status=%d\n",__LINE__, status->handle_status);
+					return;
+				}
+
+				m_unsparse_data.image_address_offset += size;
+				m_unsparse_data.chunk_remain_data_size -= size;
+				buf += size;
+				size = sizeOfX & (STORAGE_BLOCK_SIZE-1);   // size = 0 org
+				set_unsparse_status(status, STATUS_OK, UNSPARSE_WAIT_CHUNK_DATA, size, buf);
+			}
+			break;
+		}
+	default:
+		pal_log_info("sparse do nothing.\n");
+		break;
+	}
+
+	return ;
+}
+
+void write_sparse_data(unsparse_status_t* status, uint8* data, uint32 length)
+{
+	status->buf = data;
+	status->byte_to_process = length;
+	do
+	{
+		write_sparse_data_internal(status);
+
+		if (status->handle_status != STATUS_OK)
+		{
+			return;
+		}
+
+	} while (status->byte_to_process > 0);
+	return;
+}
+
+inline bool is_sparse_image(uint8* data, uint32 length)
+{
+	sparse_header_t *sparse_header = (sparse_header_t *) data;
+	return (sparse_header->magic == SPARSE_HEADER_MAGIC) ;
+}
+
+inline uint64 unspared_size(uint8* data)
+{
+	uint64 size = 0;
+	sparse_header_t *sparse_header = (sparse_header_t *) data;
+	size = (uint64)sparse_header->blk_sz * sparse_header->total_blks;
+
+	return size;
+}
+
+inline bool support_sparse_image(void)
+{
+	return true;
+}
+
+#endif
+

+ 63 - 0
app/mt_boot/mtransfer/sparse_state_machine.h

@@ -0,0 +1,63 @@
+#ifndef 	_SPARSE_STATE_MACHINE_H_
+#define 	_SPARSE_STATE_MACHINE_H_
+
+#include "transfer.h"
+
+#if defined(MTK_EMMC_SUPPORT) || defined(MTK_UFS_SUPPORT)
+#define STORAGE_BLOCK_SIZE 	4096
+#else
+#define STORAGE_BLOCK_SIZE (nand_get_alignment())
+#endif
+
+typedef enum unsparse_wait_phase
+{
+	UNSPARSE_WAIT_SPARSE_HEADER,
+	UNSPARSE_WAIT_CHUNK_HEADER,
+	UNSPARSE_WAIT_CHUNK_DATA,
+	UNSPARSE_WAIT_CHUNK_NOT_CARE,
+	UNSPARSE_WAIT_CHUNK_FILL,
+	UNSPARSE_WAIT_CHUNK_CRC,
+} unsparse_phase_t;
+
+typedef struct cache_ctx
+{
+	uint8* c_base;             //cache buffer base
+	uint32 c_offset;             //cache buffer offset
+	uint32 c_size;             //cache buffer size
+} cache_ctx_t;
+
+typedef struct unsparse_status
+{
+	status_t handle_status;
+	unsparse_phase_t wait_phase;
+	uint32 byte_to_process;    // byte to be processed in one packet.
+	uint8 *buf;                        // byte buffer of one packet.
+	cache_ctx_t ctx;           //buffer download context.
+	partition_info_struct_t* partition;
+} unsparse_status_t;
+
+
+typedef struct unsparse_data
+{
+	sparse_header_t sparse_hdr;
+	chunk_header_t chunk_hdr;
+	uint32 chunks_processed;
+	uint64 chunk_remain_data_size;      //data remained in current packet.
+	uint64 image_address_offset;         //offset of current processed data in packet    |base---|---|---|-.....|offset.....|
+	uint32 unhandle_buf_size;
+	uint8  unhandle_buf[sizeof(chunk_header_t)];
+} unsparse_data_t;
+
+bool is_sparse_image(uint8* data, uint32 length);
+bool support_sparse_image(void);
+uint64 unspared_size(uint8* data);
+void init_unsparse_status(unsparse_status_t* status,  partition_info_struct_t* partition);
+void write_sparse_data(unsparse_status_t* status, uint8* data, uint32 length);
+
+//ex functions
+void end_write_sparse_data(unsparse_status_t* status);
+
+
+#endif
+
+

+ 391 - 0
app/mt_boot/mtransfer/sparse_state_machine_nand.c

@@ -0,0 +1,391 @@
+#include <debug.h>
+#include "sparse_format.h"
+#include "sparse_state_machine.h"
+#include "transfer.h"
+#include "pal_log.h"
+
+#if (!defined(MTK_UFS_SUPPORT) && !defined(MTK_EMMC_SUPPORT))
+
+#include <platform/mtk_nand.h>
+#if defined(MTK_MLC_NAND_SUPPORT) || defined(MTK_TLC_NAND_SUPPORT)
+extern int nand_write_img(u64 addr, void *data, u32 img_sz,u64 partition_size,int partition_type);
+extern int nand_write_img_ex(u64 addr, void *data, u32 length,u64 total_size, u32 *next_offset, u64 partition_start,u64 partition_size, int img_type);
+#else
+extern int nand_write_img(u32 addr, void *data, u32 img_sz,u32 partition_size,int partition_type);
+extern int nand_write_img_ex(u32 addr, void *data, u32 length,u32 total_size, u32 *next_offset, u32 partition_start,u32 partition_size, int img_type);
+#endif
+
+
+//only engine data structure.
+static unsparse_data_t m_unsparse_data;
+
+static void write_sparse_data_internal(unsparse_status_t* status);
+
+static void set_unsparse_status( unsparse_status_t* status,
+								status_t handle_status,
+								unsparse_phase_t wait_phase,
+								uint32 size,
+								uint8 *buf	)
+{
+	status->handle_status = handle_status;
+	status->wait_phase = wait_phase;
+	status->byte_to_process = size;
+	status->buf = buf;
+}
+static void init_cache_context(unsparse_status_t* status);
+void init_unsparse_status(unsparse_status_t* status, partition_info_struct_t* partition)
+{
+	memset(status, 0, sizeof(unsparse_status_t));
+	set_unsparse_status(status, STATUS_OK, UNSPARSE_WAIT_SPARSE_HEADER, 0, 0);
+	status->partition = partition;
+	init_cache_context(status);
+}
+
+extern int nand_get_alignment();
+static void adjust_cache_size(struct cache_ctx* ctx)
+{
+	uint32 size = nand_get_alignment();
+
+	ctx->c_base = get_global_cache1();
+	ctx->c_size = size;
+	ctx->c_offset = 0;
+}
+
+static void init_cache_context(unsparse_status_t* status)
+{
+	adjust_cache_size(&status->ctx);
+}
+
+extern int get_nand_image_type(const char* arg);
+
+void end_write_sparse_data(unsparse_status_t* status)
+{
+	status->wait_phase = UNSPARSE_WAIT_CHUNK_NOT_CARE;
+	m_unsparse_data.chunk_remain_data_size = status->ctx.c_size - status->ctx.c_offset;
+	write_sparse_data_internal(status);
+}
+static void memsetint(void* p, int i, int len)
+{
+	int idx=0;
+	int count = len>>2;
+	int* buf = (int*)p;
+	while(idx < count)
+	{
+		buf[idx++] = i;
+	}
+}
+
+#define LOGDBG(...)
+static void write_sparse_data_internal(unsparse_status_t* status)
+{
+	uint32 size = status->byte_to_process;
+	uint8 *buf = status->buf;
+	int filled_seed = 0;
+	LOGDBG("+++++++++++++++++++++++++++\n");
+	LOGDBG("         slot base:[0x%x]\n", status->ctx.c_base);
+	switch (status->wait_phase)
+	{
+	case UNSPARSE_WAIT_SPARSE_HEADER:
+		{
+			LOGDBG("+ SPARSE_HEADER\n");
+			if (size >=sizeof (sparse_header_t))
+			{
+				memset((void*)&m_unsparse_data, 0x00, sizeof(unsparse_data_t));
+				memcpy((void*)&m_unsparse_data.sparse_hdr, buf, sizeof (sparse_header_t));
+
+				size -= sizeof (sparse_header_t);
+				buf+= sizeof (sparse_header_t);
+				m_unsparse_data.unhandle_buf_size = 0;
+				set_unsparse_status(status, STATUS_OK, UNSPARSE_WAIT_CHUNK_HEADER, size, buf);
+			}
+			LOGDBG("- SPARSE_HEADER\n");
+			break;
+		}
+
+	case UNSPARSE_WAIT_CHUNK_HEADER:
+		{
+			LOGDBG("+ CHUNK_HEADER\n");
+			if (m_unsparse_data.unhandle_buf_size + size >= m_unsparse_data.sparse_hdr.chunk_hdr_sz)
+			{
+				if (m_unsparse_data.unhandle_buf_size > 0)
+				{
+					uint32 sizeOfUsedBuf = m_unsparse_data.sparse_hdr.chunk_hdr_sz - m_unsparse_data.unhandle_buf_size;
+					memcpy(&m_unsparse_data.chunk_hdr, m_unsparse_data.unhandle_buf, m_unsparse_data.unhandle_buf_size);
+					memcpy( ((uint8*)&m_unsparse_data.chunk_hdr) + m_unsparse_data.unhandle_buf_size, buf, sizeOfUsedBuf);
+
+					size -= sizeOfUsedBuf;
+					buf+= sizeOfUsedBuf;
+					m_unsparse_data.unhandle_buf_size = 0;
+				}
+				else
+				{
+					memcpy(&m_unsparse_data.chunk_hdr, buf, m_unsparse_data.sparse_hdr.chunk_hdr_sz);
+					size -= m_unsparse_data.sparse_hdr.chunk_hdr_sz;
+					buf+= m_unsparse_data.sparse_hdr.chunk_hdr_sz;
+				}
+
+				m_unsparse_data.chunk_remain_data_size = (uint64)m_unsparse_data.chunk_hdr.chunk_sz*m_unsparse_data.sparse_hdr.blk_sz;
+				LOGDBG("       INFO: chunk size:[0x%llx]\n", m_unsparse_data.chunk_remain_data_size);
+				switch (m_unsparse_data.chunk_hdr.chunk_type)
+				{
+				case CHUNK_TYPE_RAW:
+					{
+						LOGDBG("                RAW\n");
+						set_unsparse_status(status, STATUS_OK, UNSPARSE_WAIT_CHUNK_DATA, size, buf);
+						break;
+					}
+				case CHUNK_TYPE_DONT_CARE:
+					{
+						LOGDBG("                DONT_CARE\n");
+						set_unsparse_status(status, STATUS_OK, UNSPARSE_WAIT_CHUNK_NOT_CARE, size, buf);
+						break;
+					}
+				case CHUNK_TYPE_FILL:
+					{
+						LOGDBG("                FILL\n");
+						set_unsparse_status(status, STATUS_OK, UNSPARSE_WAIT_CHUNK_FILL, size, buf);
+						break;
+					}
+				case CHUNK_TYPE_CRC:
+					{
+						LOGDBG("                CRC\n");
+						set_unsparse_status(status, STATUS_OK, UNSPARSE_WAIT_CHUNK_CRC, size, buf);
+						break;
+					}
+				default:
+					LOGI("@: CHUNK_TYPE_UNKNOWN: 0x%x\n", m_unsparse_data.chunk_hdr.chunk_type);
+					status->handle_status = STATUS_UNKNOWN_SPARSE_CHUNK_TYPE;
+					return;
+				}
+			}
+			else
+			{
+				LOGDBG("                HEADER SPLIT\n");
+				// LOGI("????: CHUNK_HEADER splitted.\n");
+				m_unsparse_data.unhandle_buf_size = size;
+				memcpy(m_unsparse_data.unhandle_buf, buf, size);
+				size = 0; // force to jump out while loop
+				set_unsparse_status(status, STATUS_OK, UNSPARSE_WAIT_CHUNK_HEADER, size, buf);
+			}
+			LOGDBG("- CHUNK_HEADER\n");
+			break;
+		}
+	case UNSPARSE_WAIT_CHUNK_FILL:
+		{
+			LOGDBG("+ CHUNK_FILL\n");
+			filled_seed = *(int*)buf;
+			buf += sizeof(uint32);
+			size -= sizeof(uint32);
+			while(m_unsparse_data.chunk_remain_data_size != 0)
+			{
+				uint32 slot_len = status->ctx.c_size - status->ctx.c_offset;
+
+				if(m_unsparse_data.chunk_remain_data_size >= slot_len)
+				{
+					//cache is full, so write it.
+					memsetint(status->ctx.c_base + status->ctx.c_offset, filled_seed, slot_len);
+					if (nand_write_img((u64)(status->partition->base_addr+m_unsparse_data.image_address_offset), (char*)status->ctx.c_base,  status->ctx.c_size
+						,(u64)status->partition->max_size, get_nand_image_type(status->partition->name)))
+					{
+						status->handle_status = STATUS_NAND_ERR;
+					}
+
+					if (status->handle_status  != STATUS_OK)
+					{
+						LOGDBG("[UNSPARSE] S_STORAGE_WRITE_FAILED:%d, status=%d, size=%d\n",__LINE__, status->handle_status, status->byte_to_process);
+						return;
+					}
+
+					status->ctx.c_offset = 0;// reset cache.
+					m_unsparse_data.chunk_remain_data_size -= slot_len;
+
+					m_unsparse_data.image_address_offset += status->ctx.c_size;
+
+				}
+				else
+				{
+					//fill the space with 0xFF.
+					memsetint(status->ctx.c_base + status->ctx.c_offset, filled_seed, m_unsparse_data.chunk_remain_data_size);
+					status->ctx.c_offset += m_unsparse_data.chunk_remain_data_size;
+					m_unsparse_data.chunk_remain_data_size = 0;
+				}
+			}
+
+			set_unsparse_status(status, STATUS_OK, UNSPARSE_WAIT_CHUNK_HEADER, size, buf);
+			LOGDBG("- CHUNK_FILL\n");
+			break;
+		}
+	case UNSPARSE_WAIT_CHUNK_CRC:
+		{
+			LOGDBG("+ CHUNK_CRC\n");
+			filled_seed = *(uint32*)buf;
+			buf += sizeof(uint32);
+			size -= sizeof(uint32);
+			m_unsparse_data.chunk_remain_data_size = 0;
+			set_unsparse_status(status, STATUS_OK, UNSPARSE_WAIT_CHUNK_HEADER, size, buf);
+			LOGDBG("- CHUNK_CRC\n");
+			break;
+		}
+	case UNSPARSE_WAIT_CHUNK_NOT_CARE:
+		{
+			LOGDBG("+ CHUNK_NOT_CARE\n");
+			LOGDBG("         INFO: chunk remain size:[0x%llx]\n", m_unsparse_data.chunk_remain_data_size);
+			while(m_unsparse_data.chunk_remain_data_size != 0)
+			{
+				uint32 slot_len = status->ctx.c_size - status->ctx.c_offset;
+				LOGDBG("         INFO: slot len:[0x%x]\n", slot_len);
+				if(m_unsparse_data.chunk_remain_data_size >= slot_len)
+				{
+					//cache is full, so write it.
+					if(status->ctx.c_offset != 0)
+					{
+						LOGDBG("         Write at offset:[0x%llx]\n", m_unsparse_data.image_address_offset);
+						memset(status->ctx.c_base + status->ctx.c_offset, 0xFF, slot_len);
+						if (nand_write_img((u64)(status->partition->base_addr+m_unsparse_data.image_address_offset), (char*)status->ctx.c_base,  status->ctx.c_size
+							,(u64)status->partition->max_size, get_nand_image_type(status->partition->name)))
+						{
+							status->handle_status = STATUS_NAND_ERR;
+						}
+
+						if (status->handle_status  != STATUS_OK)
+						{
+							pal_log_err("[UNSPARSE] S_STORAGE_WRITE_FAILED:%d, status=%d, size=%d\n",__LINE__, status->handle_status, status->byte_to_process);
+							return;
+						}
+					}
+					else
+					{
+						//cache is empty, do nothing to prevent from writing void data.
+					}
+					status->ctx.c_offset = 0;// reset cache.
+					m_unsparse_data.chunk_remain_data_size -= slot_len;
+
+					m_unsparse_data.image_address_offset += status->ctx.c_size;
+				}
+				else
+				{
+					//fill the space with 0xFF.
+					LOGDBG("         Set 0xff:[0x%llx]\n", m_unsparse_data.chunk_remain_data_size);
+					memset(status->ctx.c_base + status->ctx.c_offset, 0xFF, m_unsparse_data.chunk_remain_data_size);
+					status->ctx.c_offset += m_unsparse_data.chunk_remain_data_size;
+
+					m_unsparse_data.chunk_remain_data_size = 0;
+				}
+			}
+			set_unsparse_status(status, STATUS_OK, UNSPARSE_WAIT_CHUNK_HEADER, size, buf);
+			LOGDBG("- CHUNK_NOT_CARE\n");
+			break;
+		}
+	case UNSPARSE_WAIT_CHUNK_DATA:
+		{
+			LOGDBG("+ CHUNK_DATA\n");
+			uint64 this_process_len = 0;
+			if(size >= m_unsparse_data.chunk_remain_data_size)
+			{
+				this_process_len = m_unsparse_data.chunk_remain_data_size;
+			}
+			else
+			{
+				this_process_len = size;
+			}
+
+			uint32 slot_len = status->ctx.c_size - status->ctx.c_offset;
+			LOGDBG("               data left [0x%x], slot[0x%x], chunk remain [0x%llx]\n", size, slot_len, m_unsparse_data.chunk_remain_data_size);
+
+			if(slot_len <= this_process_len)
+			{
+				LOGDBG("               Write at [0x%llx]\n", m_unsparse_data.image_address_offset);
+				//cache is full.
+				memcpy(status->ctx.c_base + status->ctx.c_offset, buf, slot_len);
+
+				if (nand_write_img((u64)(status->partition->base_addr+m_unsparse_data.image_address_offset), (char*)status->ctx.c_base,  status->ctx.c_size
+					,(u64)status->partition->max_size,get_nand_image_type(status->partition->name)))
+				{
+					status->handle_status = STATUS_NAND_ERR;
+				}
+				if (status->handle_status  != STATUS_OK)
+				{
+					LOGDBG("[UNSPARSE] S_STORAGE_WRITE_FAILED:%d, status=%d, size=%d\n",__LINE__, status->handle_status, status->byte_to_process);
+					return;
+				}
+
+				buf += slot_len;
+				size -= slot_len;
+				m_unsparse_data.image_address_offset += status->ctx.c_size;
+
+				m_unsparse_data.chunk_remain_data_size -= slot_len;
+				status->ctx.c_offset = 0;// reset cache.
+
+			}
+			else
+			{
+				LOGDBG("                copy to slot[0x%x] OF data[0x%x]\n",slot_len, this_process_len);
+				//cache is not full.
+				memcpy(status->ctx.c_base + status->ctx.c_offset, buf, this_process_len);
+				status->ctx.c_offset += this_process_len;
+
+				buf += this_process_len;
+				size -= this_process_len;
+
+				m_unsparse_data.chunk_remain_data_size -= this_process_len;
+				LOGDBG("                copy to slot end\n");
+			}
+			if(m_unsparse_data.chunk_remain_data_size == 0)
+			{
+				set_unsparse_status(status, STATUS_OK, UNSPARSE_WAIT_CHUNK_HEADER, size, buf);
+			}
+			else
+			{
+				set_unsparse_status(status, STATUS_OK, UNSPARSE_WAIT_CHUNK_DATA, size, buf);
+			}
+			LOGDBG("- CHUNK_DATA\n");
+			break;
+		}
+
+	default:
+		pal_log_info("sparse image do nothing.\n");
+		break;
+	}
+	LOGDBG("---------------------------------\n");
+	return ;
+}
+
+void write_sparse_data(unsparse_status_t* status, uint8* data, uint32 length)
+{
+	status->buf = data;
+	status->byte_to_process = length;
+	do
+	{
+		write_sparse_data_internal(status);
+
+		if (status->handle_status != STATUS_OK)
+		{
+			return;
+		}
+
+	} while (status->byte_to_process > 0);
+	return;
+}
+
+inline bool is_sparse_image(uint8* data, uint32 length)
+{
+	sparse_header_t *sparse_header = (sparse_header_t *) data;
+	return (sparse_header->magic == SPARSE_HEADER_MAGIC) ;
+}
+
+inline uint64 unspared_size(uint8* data)
+{
+	uint64 size = 0;
+	sparse_header_t *sparse_header = (sparse_header_t *) data;
+	size = sparse_header->blk_sz * sparse_header->total_blks;
+
+	return size;
+}
+
+inline bool support_sparse_image(void)
+{
+	return true;
+}
+
+#endif
+

+ 62 - 0
app/mt_boot/mtransfer/transfer.h

@@ -0,0 +1,62 @@
+#ifndef __M_TRANSFER_H
+#define __M_TRANSFER_H
+
+#define MAX_PARTITION_NAME_LEN 32
+
+
+#define ROUND_TO_PAGE(x,y) (((x) + (y)) & (~(y)))
+#define PARTITION_NAME_SIZE  MAX_PARTITION_NAME_LEN
+#define MAX_EXT_SIG_LEN (2*1024*1024)
+
+#define STATUS_OK 0
+#define STATUS_INVALID_PARAMETERS 	(-100)
+#define STATUS_TOO_LARGE 			(-101)
+#define STATUS_USB_ERR 				(-102)
+#define STATUS_EMMC_ERR 			(-103)
+#define STATUS_NAND_ERR 			(-104)
+#define STATUS_THREAD 				(-105)
+#define STATUS_UNKNOWN_SPARSE_CHUNK_TYPE 	(-106)
+
+#define STATUS_SPARSE_INCOMPLETE  (100)
+#define FAIL(code) 		(((status_t)(code)) < 0)
+
+typedef  unsigned char uint8;
+typedef  unsigned int uint32;
+typedef  unsigned long long uint64;
+
+#define LOGI _dprintf
+#define LOGE _dprintf
+
+
+
+typedef struct partition_info_struct
+{
+	uint8  name[PARTITION_NAME_SIZE];
+	uint64 base_addr;
+	uint64 max_size;
+	int part_id;
+}partition_info_struct_t;
+
+
+typedef struct download_data_context {
+	bool first_run;
+	uint64 bytes_written;
+	uint64 length_to_write;
+	partition_info_struct_t *part_info;
+} download_data_context_t;
+
+
+static inline void init_download_data_context(download_data_context_t* data_ctx, uint64 data_length, partition_info_struct_t* part_info)
+{
+	data_ctx->first_run = 1;
+	data_ctx->bytes_written = 0;
+	data_ctx->length_to_write = data_length;
+	data_ctx->part_info = part_info;
+}
+
+status_t download_data(uint64 data_length, partition_info_struct_t* part_info);
+uint8* get_global_cache1();
+
+#endif
+
+

+ 377 - 0
app/mt_boot/mtransfer/transfer_parallel.c

@@ -0,0 +1,377 @@
+
+#include <stdlib.h>
+#include <app.h>
+#include <debug.h>
+#include <arch/arm.h>
+#include <dev/udc.h>
+#include <string.h>
+#include <kernel/thread.h>
+#include <kernel/event.h>
+#include <arch/ops.h>
+#include <target.h>
+#include <platform.h>
+#include <platform/mt_gpt.h>
+
+#include "dl_commands.h"
+
+#include "sparse_format.h"
+#include "transfer.h"
+#include "sparse_state_machine.h"
+#include "bulk_process.h"
+
+#if defined MTK_ULTRA_FLASH
+
+#define TIME_STAMP gpt4_tick2time_ms(gpt4_get_current_tick())
+
+
+#define CACHE_PADDING_SIZE 	STORAGE_BLOCK_SIZE
+#define SYSOB_CACHE_PAGE   2*1024*1024U
+#define SYSOB_BIG_CACHE   2*1024*1024U
+#define SIGNAL_RESCHEDULE 0  //true; active. 0 passive.
+
+/***********************************************************************************
+*                  DOWNLOAD ENGINE
+***********************************************************************************/
+typedef enum engine_op_part
+{
+	EOP_DATA_PROVIDER,
+	EOP_DATA_CONSUMER,
+}engine_part_e;
+
+typedef struct cache
+{
+	uint8* padding_buf;
+	uint8* cache_buf;
+	uint32 padding_length;  //sparse image boundary problem.
+	uint32 content_length;  //if this is 0, indicate this the last package.
+	event_t content_available;
+	event_t cache_available;
+}cache_t;
+
+
+typedef struct engine_context
+{
+	uint8* cache_base;
+	cache_t dual_cache[2];
+	uint32 flipIdxR;     //receive buffer shift
+	uint32 flipIdxW;    //write buffer shift
+	event_t thrR_end_ev; // recieve thread exit sync.
+	event_t thrW_end_ev; // write thread exit sync.
+	status_t status_usb ; // if something is wrong, should exit.
+	status_t status_storage ; // if something is wrong, should exit.
+}engine_context_t;
+
+
+static engine_context_t* ctx;
+
+#define ALIGN_SZ (64)
+
+#define MM_BASE get_available_ram_base()
+#define MM_1ST_16M (((uint8*)get_available_ram_base())+3*SYSOB_BIG_CACHE)
+
+extern uint8* get_global_cache1()
+{
+	return MM_1ST_16M;
+}
+
+void init_engine_context(engine_context_t* tx)
+{
+	/*dual cache pattern:     | PADDING1 | CACHE1 || PADDING2 | CACHE2 |*/
+	uint32 CACHE_PAGE_SIZE = SYSOB_CACHE_PAGE;
+	//uint32 DCACHE_SIZE  = (2*CACHE_PAGE_SIZE+2*CACHE_PADDING_SIZE);
+
+	tx->cache_base = (uint8*)get_available_ram_base();
+
+	tx->dual_cache[0].padding_buf = tx->cache_base;
+	tx->dual_cache[0].cache_buf = tx->cache_base+CACHE_PADDING_SIZE;
+	tx->dual_cache[1].padding_buf = tx->cache_base+CACHE_PADDING_SIZE+CACHE_PAGE_SIZE;
+	tx->dual_cache[1].cache_buf = tx->cache_base+CACHE_PADDING_SIZE+CACHE_PAGE_SIZE+CACHE_PADDING_SIZE;
+
+	tx->dual_cache[0].padding_length = tx->dual_cache[1].padding_length = 0;
+
+	event_init(&tx->dual_cache[0].content_available, 0, EVENT_FLAG_AUTOUNSIGNAL);//no data in cache
+	event_init(&tx->dual_cache[1].content_available, 0, EVENT_FLAG_AUTOUNSIGNAL);//no data in cache
+
+	event_init(&tx->dual_cache[0].cache_available, 1, EVENT_FLAG_AUTOUNSIGNAL);    //can receive from usb
+	event_init(&tx->dual_cache[1].cache_available, 1, EVENT_FLAG_AUTOUNSIGNAL);    //can receive from usb
+
+	event_init(&tx->thrR_end_ev, 0, EVENT_FLAG_AUTOUNSIGNAL);//do not end.
+	event_init(&tx->thrW_end_ev, 0, EVENT_FLAG_AUTOUNSIGNAL);//do not end.
+	tx->status_usb = STATUS_OK;
+	tx->status_storage = STATUS_OK;
+	tx->flipIdxR = tx->flipIdxW = 0;
+
+}
+
+inline uint32 cache_shift(uint32 pre)
+{
+	return pre ^ 0x01;
+}
+
+void stop_engine(engine_context_t * tx, engine_part_e part)
+{
+	if(part == EOP_DATA_CONSUMER)
+	{
+		event_signal(&tx->dual_cache[0].cache_available, SIGNAL_RESCHEDULE);
+		event_signal(&tx->dual_cache[1].cache_available, SIGNAL_RESCHEDULE);
+		event_signal(&tx->thrR_end_ev, SIGNAL_RESCHEDULE);
+	}
+	else if(part == EOP_DATA_PROVIDER)
+	{
+		event_signal(&tx->dual_cache[0].content_available, SIGNAL_RESCHEDULE);
+		event_signal(&tx->dual_cache[1].content_available, SIGNAL_RESCHEDULE);
+		event_signal(&tx->thrW_end_ev, SIGNAL_RESCHEDULE);
+	}
+}
+
+void destroy_engine(engine_context_t* tx)
+{
+	event_destroy(&tx->dual_cache[0].cache_available);
+	event_destroy(&tx->dual_cache[1].cache_available);
+	event_destroy(&tx->dual_cache[0].content_available);
+	event_destroy(&tx->dual_cache[1].content_available);
+	event_destroy(&tx->thrR_end_ev);
+	event_destroy(&tx->thrW_end_ev);
+
+	tx->cache_base = 0;
+}
+/***********************************************************************************
+*                  DOWNLOAD
+***********************************************************************************/
+
+static download_data_context_t* write_data_ctx = 0;
+
+status_t write_data(uint8* data, uint32 length)
+{
+	uint32 next_flip = 0;
+	static unsparse_status_t unsparse_status; //sparse image parsing used.
+	static bulk_status_t bulk_status; //bulk image parsing used.
+	static bool is_sparse = false;
+	uint64 total_image_length = 0;//if sparse image, it should be size after unsparsed.
+
+
+	if(data == 0)
+	{
+		return STATUS_INVALID_PARAMETERS;
+	}
+
+	if(write_data_ctx->first_run)
+	{
+		is_sparse = is_sparse_image(data, length);
+		total_image_length = write_data_ctx->length_to_write;
+
+		if(is_sparse)
+		{
+			init_unsparse_status(&(unsparse_status),  write_data_ctx->part_info);
+			total_image_length = unspared_size(data);
+		}
+		else
+		{
+			init_bulk_process_status(&(bulk_status),  write_data_ctx->part_info);
+			total_image_length = write_data_ctx->length_to_write;
+		}
+
+		if (total_image_length> write_data_ctx->part_info->max_size)
+		{
+			LOGE( "size too large, space small. image length[0x%llx], partition max size[0x%llx]\n",
+				total_image_length,  write_data_ctx->part_info->max_size);
+			return STATUS_TOO_LARGE;
+		}
+		//The first run flag will be reset later after erase_before_download finished.
+		write_data_ctx->first_run = 0;
+	}
+
+	if (is_sparse)
+	{
+		next_flip = cache_shift(ctx->flipIdxR);
+
+		if(length != 0)
+		{
+			write_sparse_data(&unsparse_status, data, length);
+			if (unsparse_status.handle_status == STATUS_SPARSE_INCOMPLETE)
+			{
+				memcpy(ctx->dual_cache[next_flip].padding_buf +(CACHE_PADDING_SIZE-unsparse_status.byte_to_process)
+					, unsparse_status.buf
+					, unsparse_status.byte_to_process);
+				ctx->dual_cache[next_flip].padding_length = unsparse_status.byte_to_process;
+				unsparse_status.handle_status = STATUS_OK;
+			}
+			else if (unsparse_status.handle_status== STATUS_OK)
+			{
+				ctx->dual_cache[next_flip].padding_length = 0;
+			}
+		}
+		else
+		{
+			//the last package.
+			end_write_sparse_data(&unsparse_status);
+		}
+	}
+	else
+	{
+		if (length != 0)
+		{
+			write_bulk_data(&bulk_status, data, length);
+		}
+		else
+		{//the last package.
+			end_write_bulk(&bulk_status);
+		}
+	}
+	return unsparse_status.handle_status;
+
+}
+
+
+int write_storage_proc(void *arg)
+{
+	uint8* data = 0;
+	uint32 data_len = 0;
+
+	//LOGI("\nin write_storage_proc\n");
+
+	for (;;)
+	{
+		event_wait(&(ctx->dual_cache[ctx->flipIdxR].content_available));
+
+		if(FAIL(ctx->status_usb))
+		{
+			goto exit;
+		}
+
+		//if has something to write
+		data = (uint8*)(ctx->dual_cache[ctx->flipIdxR].cache_buf);
+		data_len = ctx->dual_cache[ctx->flipIdxR].content_length;
+
+		data -= ctx->dual_cache[ctx->flipIdxR].padding_length;
+		data_len += ctx->dual_cache[ctx->flipIdxR].padding_length;
+		ctx->status_storage = write_data(data, data_len);
+
+		if(ctx->status_storage != STATUS_OK)
+		{
+			//error
+			LOGE("write data failed. handle_status(%d)\n", ctx->status_storage);
+			goto exit;
+		}
+
+		//last package, should return;
+		if (ctx->dual_cache[ctx->flipIdxR].content_length == 0)
+		{
+			break;
+		}
+		event_signal(&ctx->dual_cache[ctx->flipIdxR].cache_available, SIGNAL_RESCHEDULE); //make this cache writeable again.
+
+		ctx->flipIdxR = cache_shift(ctx->flipIdxR); //change next buffer.
+	}
+
+exit:
+	stop_engine(ctx, EOP_DATA_CONSUMER);
+	thread_exit(0);
+	//never arrive here.
+	return 0;
+}
+
+extern int usb_read(void *_buf, unsigned len);
+void read_usb_proc(uint64 data_length)
+{
+	uint64 bytes_already_read = 0;
+	uint64 bytes_to_read = 0;
+	uint32 CACHE_PAGE_SIZE = SYSOB_CACHE_PAGE;
+	uint32 TOTAL_CACHE_PAGE_SIZE = SYSOB_BIG_CACHE;
+
+	while (bytes_already_read  < data_length)
+	{
+		event_wait(&(ctx->dual_cache[ctx->flipIdxW].cache_available));
+
+		ctx->dual_cache[ctx->flipIdxW].content_length = 0;
+		uint32 cache_offset = 0;
+		while((cache_offset < TOTAL_CACHE_PAGE_SIZE) && (bytes_already_read  < data_length))
+		{
+			bytes_to_read = data_length - bytes_already_read;
+			bytes_to_read = bytes_to_read >= CACHE_PAGE_SIZE ? CACHE_PAGE_SIZE : bytes_to_read;
+
+			//LOGI("$$ Read usb length 0x%llx, buf addr at 0x%x\n", bytes_to_read, ctx->dual_cache[ctx->flipIdxW].cache_buf+cache_offset);
+			int r = usb_read(ctx->dual_cache[ctx->flipIdxW].cache_buf+cache_offset, (unsigned int)bytes_to_read);
+			if ((r < 0) || ((unsigned int) r != (unsigned int)bytes_to_read))
+			{
+				ctx->status_usb = STATUS_USB_ERR;
+				LOGE("Read usb error. code 0x%x\n", ctx->status_usb);
+				goto exit;
+			}
+
+			ctx->dual_cache[ctx->flipIdxW].content_length += bytes_to_read;
+			bytes_already_read += bytes_to_read;
+			cache_offset += bytes_to_read;
+
+			if(FAIL(ctx->status_usb) || FAIL(ctx->status_storage))
+			{
+				// storage write error.
+				goto exit;
+			}
+			display_progress("\rFlash: ", bytes_already_read, write_data_ctx->length_to_write);
+		}
+
+		event_signal(&ctx->dual_cache[ctx->flipIdxW].content_available, SIGNAL_RESCHEDULE);
+		ctx->flipIdxW = cache_shift(ctx->flipIdxW); //change next buffer.
+	}
+
+	//last package.
+	//must wait for this can write again. wait for storage write finish.
+	event_wait(&(ctx->dual_cache[ctx->flipIdxW].cache_available));
+	//notify finish info to storage write thread with zero length packet.
+	ctx->dual_cache[ctx->flipIdxW].content_length = 0;
+	event_signal(&ctx->dual_cache[ctx->flipIdxW].content_available, SIGNAL_RESCHEDULE);
+
+exit:
+	stop_engine(ctx, EOP_DATA_PROVIDER);
+	return;
+}
+
+
+status_t download_data(uint64 data_length, partition_info_struct_t* part_info)//Big image and parallel transfer.
+{
+	thread_t *thr;
+	download_data_context_t data_ctx;
+	engine_context_t engine_ctx;
+
+#ifdef DUMP_SPEED
+	uint32 time_start = 0;
+	uint32 time_end = 0;
+#endif
+
+	write_data_ctx = &data_ctx;
+	ctx = &engine_ctx;
+	init_engine_context(ctx);
+	init_download_data_context(write_data_ctx, data_length, part_info);
+
+#ifdef DUMP_SPEED
+	time_start = TIME_STAMP;
+#endif
+	thr = thread_create("write_storage_proc", write_storage_proc, 0, HIGHEST_PRIORITY, 16*1024);
+	if (!thr)
+	{
+		LOGE("create write_storage_proc thread failed.");
+		return STATUS_THREAD;
+	}
+	thread_resume(thr);
+	read_usb_proc(data_length);
+
+	//wait for thread end.
+	event_wait(&ctx->thrR_end_ev);
+	event_wait(&ctx->thrW_end_ev);
+
+#ifdef DUMP_SPEED
+	time_end = TIME_STAMP;
+#endif
+
+	destroy_engine(ctx);
+
+	LOGI("Process download_data Finish.\n");
+
+	return FAIL(ctx->status_storage) ? ctx->status_storage : ctx->status_usb;
+}
+
+
+
+#endif
+

+ 379 - 0
app/mt_boot/odm_mdtbo.c

@@ -0,0 +1,379 @@
+/* Copyright Statement:
+*
+* This software/firmware and related documentation ("MediaTek Software") are
+* protected under relevant copyright laws. The information contained herein
+* is confidential and proprietary to MediaTek Inc. and/or its licensors.
+* Without the prior written permission of MediaTek inc. and/or its licensors,
+* any reproduction, modification, use or disclosure of MediaTek Software,
+* and information contained herein, in whole or in part, shall be strictly prohibited.
+*/
+/* MediaTek Inc. (C) 2017. All rights reserved.
+*
+* BY OPENING THIS FILE, RECEIVER HEREBY UNEQUIVOCALLY ACKNOWLEDGES AND AGREES
+* THAT THE SOFTWARE/FIRMWARE AND ITS DOCUMENTATIONS ("MEDIATEK SOFTWARE")
+* RECEIVED FROM MEDIATEK AND/OR ITS REPRESENTATIVES ARE PROVIDED TO RECEIVER ON
+* AN "AS-IS" BASIS ONLY. MEDIATEK EXPRESSLY DISCLAIMS ANY AND ALL WARRANTIES,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED WARRANTIES OF
+* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE OR NONINFRINGEMENT.
+* NEITHER DOES MEDIATEK PROVIDE ANY WARRANTY WHATSOEVER WITH RESPECT TO THE
+* SOFTWARE OF ANY THIRD PARTY WHICH MAY BE USED BY, INCORPORATED IN, OR
+* SUPPLIED WITH THE MEDIATEK SOFTWARE, AND RECEIVER AGREES TO LOOK ONLY TO SUCH
+* THIRD PARTY FOR ANY WARRANTY CLAIM RELATING THERETO. RECEIVER EXPRESSLY ACKNOWLEDGES
+* THAT IT IS RECEIVER'S SOLE RESPONSIBILITY TO OBTAIN FROM ANY THIRD PARTY ALL PROPER LICENSES
+* CONTAINED IN MEDIATEK SOFTWARE. MEDIATEK SHALL ALSO NOT BE RESPONSIBLE FOR ANY MEDIATEK
+* SOFTWARE RELEASES MADE TO RECEIVER'S SPECIFICATION OR TO CONFORM TO A PARTICULAR
+* STANDARD OR OPEN FORUM. RECEIVER'S SOLE AND EXCLUSIVE REMEDY AND MEDIATEK'S ENTIRE AND
+* CUMULATIVE LIABILITY WITH RESPECT TO THE MEDIATEK SOFTWARE RELEASED HEREUNDER WILL BE,
+* AT MEDIATEK'S OPTION, TO REVISE OR REPLACE THE MEDIATEK SOFTWARE AT ISSUE,
+* OR REFUND ANY SOFTWARE LICENSE FEES OR SERVICE CHARGE PAID BY RECEIVER TO
+* MEDIATEK FOR SUCH MEDIATEK SOFTWARE AT ISSUE.
+*/
+
+#include <odm_mdtbo.h>                  // for get_odm_mdtbo_index()
+#include <debug.h>                      // for dprintf()
+#include <part_interface.h>             // for partition_read()
+#include <part_status.h>
+#include <block_generic_interface.h>    // for mt_part_get_device()
+#include <stdlib.h>                     // for malloc()
+#include <libfdt.h>
+#include <img_info.h>
+#include <rsc.h>
+
+/* global variable to send androidboot.dtbo_idx */
+static int hw_mdtbo_index = -1;
+int get_dtbo_index(void)
+{
+	if (hw_mdtbo_index == -1)
+		panic("hw_mdtbo_index is not inited!\n");
+	return hw_mdtbo_index;
+}
+void set_dtbo_index(int dtbo_idx)
+{
+	hw_mdtbo_index = dtbo_idx;
+}
+
+/******************************************************************************
+* NOTE: Customers need to implement their own customized_get_odm_mdtbo_index()
+*       function. If customized_get_odm_mdtbo_index() is not implemented, the
+*       value 0 will be used as the default dtbo index. Each customer can
+*       maintain their own implementation of customized_get_odm_mdtbo_index()
+*       in a separate source file as long as it can be linked.
+******************************************************************************/
+int get_odm_mdtbo_index(void)
+{
+	int odm_dtbo_index = 0;
+	int rsc_is_valid = 0;
+
+	if (rsc_get_dtbo_index) {
+		rsc_is_valid = rsc_valid();
+		if (rsc_is_valid)
+			odm_dtbo_index = rsc_get_dtbo_index();
+	}
+	if (!rsc_is_valid) {
+		if (customized_get_odm_mdtbo_index)
+			odm_dtbo_index = customized_get_odm_mdtbo_index();
+	}
+	return odm_dtbo_index;
+}
+
+
+/******************************************************************************
+******************************************************************************/
+static bool is_odm_mdtbo_header(const mdtbo_hdr_t *hdr2)
+{
+	if (hdr2->info.magic != ODM_MDTBO_MAGIC) {
+		dprintf(INFO, "Single ODM DTBO.\n");
+		return false;
+	}
+	dprintf(INFO, "Multiple ODM DTBO.\n");
+	return true;
+}
+
+
+/******************************************************************************
+* dtb_size:   It is the size of the device tree selected by dtbo_index.
+* dtb_offset: It is the offset from the beginning of the partition.
+******************************************************************************/
+static void get_odm_mdtbo_offset_and_size(const mdtbo_hdr_t *hdr2,
+	int mdtbo_index, unsigned int *dtbo_size, unsigned int *dtbo_offset)
+{
+	if (mdtbo_index < 0 || mdtbo_index >= MAX_NUM_OF_ODM_MDTBO) {
+		goto fail;
+	}
+
+	if ((unsigned int)mdtbo_index == hdr2->info.num_of_dtbo - 1)
+		*dtbo_size = hdr2->info.dsize;
+	else {
+		if ((mdtbo_index+1) >= MAX_NUM_OF_ODM_MDTBO)
+			goto fail;
+		*dtbo_size = hdr2->info.dtbo_offset[mdtbo_index + 1];
+	}
+
+	if (*dtbo_size <= hdr2->info.dtbo_offset[mdtbo_index]) {
+		dprintf(CRITICAL, "Error: incorrect dtbo size\n");
+		assert(0);
+	}
+	*dtbo_size -= hdr2->info.dtbo_offset[mdtbo_index];
+
+	*dtbo_offset = hdr2->info.dtbo_offset[mdtbo_index];
+	*dtbo_offset += PART_HDR_DATA_SIZE + ODM_MDTBO_HDR_SIZE;
+	return;
+
+fail:
+	dprintf(CRITICAL, "Error: mdtbo index %d is out of range!\n", mdtbo_index);
+	assert(0);
+}
+
+
+/******************************************************************************
+* Side effect: This function allocates a memory on success.
+******************************************************************************/
+static bool load_dtb_from_single_dtbo(char *part_name, union mkimg_hdr *img_hdr,
+	char **handle, uint64_t recovery_dtbo_offset)
+{
+	unsigned int dsize = img_hdr->info.dsz;
+	*handle = malloc(dsize);
+	if (*handle == NULL) {
+		dprintf(CRITICAL, "Fail to malloc %d-byte buffer for dtbo!\n", dsize);
+		assert(0);
+		return false;
+	}
+
+	long len = partition_read(part_name, (off_t)(recovery_dtbo_offset+PART_HDR_DATA_SIZE), (uchar*)*handle, (size_t)dsize);
+	if (len < 0) {
+		dprintf(CRITICAL, "(L%d) Fail to read %s partition!\n", __LINE__, part_name);
+		free(*handle);
+		return false;
+	}
+
+	if (fdt_magic(*handle) != FDT_MAGIC) {
+		dprintf(CRITICAL, "Error: invalid dtbo image format!\n");
+		free(*handle);
+		assert(0);  // Keep running instead of assert!!
+		return false;
+	}
+
+	return true;
+}
+
+
+/******************************************************************************
+* Side effect: This function allocates a memory on success.
+******************************************************************************/
+static bool load_dtb_from_multiple_dtbo(char *part_name,
+	const mdtbo_hdr_t *hdr2, char **handle, uint64_t recovery_dtbo_offset)
+{
+	if (hdr2->info.hdr_size != ODM_MDTBO_HDR_SIZE) {
+		dprintf(CRITICAL, "Error: odm mdtbo header size %d mismatch!\n",
+			hdr2->info.hdr_size);
+		assert(0);
+		return false;
+	}
+
+	if (hdr2->info.hdr_version != ODM_MDTBO_VERSION) {
+		dprintf(CRITICAL, "Error: odm mdtbo header version %d mismatch!\n",
+			hdr2->info.hdr_version);
+		assert(0);
+		return false;
+	}
+
+	hw_mdtbo_index = get_odm_mdtbo_index();
+	if (hw_mdtbo_index < 0 || hw_mdtbo_index >= MAX_NUM_OF_ODM_MDTBO) {
+		dprintf(CRITICAL, "Error: mdtbo index %d is out of range!\n", hw_mdtbo_index);
+		assert(0);
+		return false;
+	}
+
+	unsigned int dtbo_size = 0, dtbo_offset = 0;
+	if ((unsigned int)hw_mdtbo_index >= hdr2->info.num_of_dtbo) {
+		dprintf(CRITICAL, "Error: hw_mdtbo_index %d >= num_of_dtbo %d.\n",
+			hw_mdtbo_index, hdr2->info.num_of_dtbo);
+		dprintf(CRITICAL, "Set hw_mdtbo_index to 0 for error handling!\n");
+		hw_mdtbo_index = 0;
+	}
+	get_odm_mdtbo_offset_and_size(hdr2, hw_mdtbo_index, &dtbo_size, &dtbo_offset);
+	dprintf(INFO, "ODM hw_mdtbo_index: %d, dtbo_offset: %d, dtbo_size: %d\n",
+		hw_mdtbo_index, dtbo_offset, dtbo_size);
+
+	*handle = malloc(dtbo_size);
+	if (!*handle) {
+		dprintf(CRITICAL, "Fail to malloc %d-byte buffer for dtbo!\n", dtbo_size);
+		assert(0);
+		return false;
+	}
+
+	long len = partition_read(part_name, (off_t)(recovery_dtbo_offset+dtbo_offset), (uchar*)*handle, (size_t)dtbo_size);
+	if (len < 0) {
+		dprintf(CRITICAL, "(L%d) Fail to read %s partition!\n", __LINE__, part_name);
+		free(*handle);
+		return false;
+	}
+
+	if (fdt_magic(*handle) != FDT_MAGIC) {
+		dprintf(CRITICAL, "Error: invalid dtbo image format!\n");
+		free(*handle);
+		assert(0);  // Keep running instead of assert!!
+		return false;
+	}
+
+	return true;
+}
+
+/******************************************************************************
+* Load function from new dtb partition format defined since Android P
+******************************************************************************/
+static bool load_dtb_from_dtb_entry(char *part_name,
+	const struct dt_table_header *hdr2, char **handle, uint64_t recovery_dtbo_offset)
+{
+	unsigned int i, dtbo_size = 0, dtbo_offset = 0;
+	const struct dt_table_entry *hdr3 = (struct dt_table_entry *)(hdr2 + 1);
+
+	if (fdt32_to_cpu(hdr2->header_size) != sizeof(struct dt_table_header)) {
+		dprintf(CRITICAL, "Error: dt_table_header size %d mismatch!\n",
+			fdt32_to_cpu(hdr2->header_size));
+		assert(0);
+		return false;
+	}
+
+	if (fdt32_to_cpu(hdr2->dt_entry_size) != sizeof(struct dt_table_entry)) {
+		dprintf(CRITICAL, "Error: dt_table_entry size %d mismatch!\n",
+			fdt32_to_cpu(hdr2->dt_entry_size));
+		assert(0);
+		return false;
+	}
+
+	hw_mdtbo_index = get_odm_mdtbo_index();
+
+	/* traverse hw_mdtbo_index into dt_table_entry->id */
+	for(i = 0; i < fdt32_to_cpu(hdr2->dt_entry_count); i++) {
+		if ((unsigned int)hw_mdtbo_index == fdt32_to_cpu((hdr3 + i)->id)) {
+			hw_mdtbo_index = i;
+			dprintf(CRITICAL, "real mdtbo index=%d\n", hw_mdtbo_index);
+			break;
+		}
+	}
+	/* traverse end */
+
+	if ((unsigned int)hw_mdtbo_index >= fdt32_to_cpu(hdr2->dt_entry_count)) {
+		dprintf(CRITICAL, "Set hw_mdtbo_index to 0 for error handling!\n");
+		hw_mdtbo_index = 0;
+	}
+
+	hdr3 = (struct dt_table_entry *)(hdr3 + hw_mdtbo_index);
+	dtbo_size = fdt32_to_cpu(hdr3->dt_size);
+	dtbo_offset = fdt32_to_cpu(hdr3->dt_offset);
+	dprintf(INFO, "hw_mdtbo_index: %d, dtbo_offset: %d, dtbo_size: %d\n",
+		hw_mdtbo_index, dtbo_offset, dtbo_size);
+
+	*handle = malloc(dtbo_size);
+	if (!*handle) {
+		dprintf(CRITICAL, "Fail to malloc %d-byte buffer for dtbo!\n", dtbo_size);
+		assert(0);
+		return false;
+	}
+
+	long len = partition_read(part_name, (off_t)(recovery_dtbo_offset+dtbo_offset), (uchar*)*handle, (size_t)dtbo_size);
+	if (len < 0) {
+		dprintf(CRITICAL, "(L%d) Fail to read %s partition!\n", __LINE__, part_name);
+		free(*handle);
+		return false;
+	}
+
+	if ((fdt_magic(*handle) != FDT_MAGIC)||(fdt_totalsize(*handle) != dtbo_size)) {
+		dprintf(CRITICAL, "Error: invalid dtbo image format!\n");
+		free(*handle);
+		assert(0);
+		return false;
+	}
+
+	return true;
+}
+
+/******************************************************************************
+******************************************************************************/
+char *load_overlay_dtbo(char *part_name, unsigned int *size, uint64_t recovery_dtbo_offset)
+{
+	if (sizeof(union mkimg_hdr) != PART_HDR_DATA_SIZE) {
+		dprintf(CRITICAL, "Error: incorrect partition header size!\n");
+		assert(0);
+		return NULL;
+	}
+
+	if (size == NULL) {
+		dprintf(CRITICAL, "(L%d) Error: size is NULL!\n", __LINE__);
+		return NULL;
+	}
+
+	if (partition_exists(part_name) != PART_OK) {
+		dprintf(CRITICAL, "(L%d) Fail to get partition %s!\n", __LINE__, part_name);
+		return NULL;
+	}
+
+	/* Read the partition header & the trailing 32 bytes for possible prolog. */
+	long read_size = (long)(PART_HDR_DATA_SIZE + ODM_MDTBO_HDR_SIZE + LARGE_DT_ENTRY_SIZE);
+	union mkimg_hdr *img_hdr = (union mkimg_hdr *)malloc(read_size);
+	if (img_hdr == NULL) {
+		dprintf(CRITICAL, "(L%d) Fail to allocate %d-byte memory!\n", __LINE__, (int)read_size);
+		return NULL;
+	}
+
+	/* Read mkimage header. Treat it as the mdtbo header. */
+	long len = partition_read(part_name, (off_t)recovery_dtbo_offset, (uchar*)img_hdr, (size_t)read_size);
+	if (len < 0) {
+		dprintf(CRITICAL, "(L%d) Fail to read %s partition!\n", __LINE__, part_name);
+		free(img_hdr);
+		return NULL;
+	}
+
+	/* Legacy MKIMG+MDTBO header parsing */
+	if ((MKIMG_MAGIC == img_hdr->info.magic) && (MKIMG_EXT_MAGIC == img_hdr->info.ext_magic)) {
+
+		/* hdr2 points to the possible prolog. */
+		const mdtbo_hdr_t *hdr2 = (mdtbo_hdr_t*)(img_hdr + 1);
+		char *ptr = NULL;
+		bool success = false;
+		if (is_odm_mdtbo_header(hdr2) == false)
+			success = load_dtb_from_single_dtbo(part_name, img_hdr, &ptr, (uint64_t)recovery_dtbo_offset);
+		else
+			success = load_dtb_from_multiple_dtbo(part_name, hdr2, &ptr, (uint64_t)recovery_dtbo_offset);
+
+		free(img_hdr);
+		if (success) {
+			*size = fdt32_to_cpu(*(unsigned int *)(ptr + 4));
+			return ptr;
+		}
+	/* New DTBO parsing using dt_table_header/dt_table_entry */
+	} else if (DT_TABLE_MAGIC == fdt_magic(img_hdr)) {
+		const struct dt_table_header *hdr2 = (struct dt_table_header *)img_hdr;
+		unsigned int dt_entries_offset = fdt32_to_cpu(hdr2->dt_entries_offset);
+		unsigned int dt_entry_count = fdt32_to_cpu(hdr2->dt_entry_count);
+		unsigned int dt_entry_size = fdt32_to_cpu(hdr2->dt_entry_size);
+		char *ptr = NULL;
+		bool success = false;
+
+		if ((PART_HDR_DATA_SIZE + ODM_MDTBO_HDR_SIZE + LARGE_DT_ENTRY_SIZE) <
+			(dt_entries_offset + dt_entry_count * dt_entry_size)){
+			dprintf(CRITICAL, "error handle: need to load more dt_entry size = (%d)!\n",
+				(dt_entries_offset + dt_entry_count * dt_entry_size));
+			assert(0);
+			return NULL;
+		}
+
+		success = load_dtb_from_dtb_entry(part_name, hdr2, &ptr, (uint64_t)recovery_dtbo_offset);
+
+		free(img_hdr);
+		if (success) {
+			*size = fdt32_to_cpu(*(unsigned int *)(ptr + 4));
+			return ptr;
+		}
+	}
+	else {
+		dprintf(CRITICAL, "assert: non of any known dtbo format !\n");
+		assert(0);
+		return NULL;
+	}
+
+	return NULL;
+}
+
+

+ 125 - 0
app/mt_boot/odm_mdtbo.h

@@ -0,0 +1,125 @@
+/* Copyright Statement:
+*
+* This software/firmware and related documentation ("MediaTek Software") are
+* protected under relevant copyright laws. The information contained herein
+* is confidential and proprietary to MediaTek Inc. and/or its licensors.
+* Without the prior written permission of MediaTek inc. and/or its licensors,
+* any reproduction, modification, use or disclosure of MediaTek Software,
+* and information contained herein, in whole or in part, shall be strictly prohibited.
+*/
+/* MediaTek Inc. (C) 2017. All rights reserved.
+*
+* BY OPENING THIS FILE, RECEIVER HEREBY UNEQUIVOCALLY ACKNOWLEDGES AND AGREES
+* THAT THE SOFTWARE/FIRMWARE AND ITS DOCUMENTATIONS ("MEDIATEK SOFTWARE")
+* RECEIVED FROM MEDIATEK AND/OR ITS REPRESENTATIVES ARE PROVIDED TO RECEIVER ON
+* AN "AS-IS" BASIS ONLY. MEDIATEK EXPRESSLY DISCLAIMS ANY AND ALL WARRANTIES,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED WARRANTIES OF
+* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE OR NONINFRINGEMENT.
+* NEITHER DOES MEDIATEK PROVIDE ANY WARRANTY WHATSOEVER WITH RESPECT TO THE
+* SOFTWARE OF ANY THIRD PARTY WHICH MAY BE USED BY, INCORPORATED IN, OR
+* SUPPLIED WITH THE MEDIATEK SOFTWARE, AND RECEIVER AGREES TO LOOK ONLY TO SUCH
+* THIRD PARTY FOR ANY WARRANTY CLAIM RELATING THERETO. RECEIVER EXPRESSLY ACKNOWLEDGES
+* THAT IT IS RECEIVER'S SOLE RESPONSIBILITY TO OBTAIN FROM ANY THIRD PARTY ALL PROPER LICENSES
+* CONTAINED IN MEDIATEK SOFTWARE. MEDIATEK SHALL ALSO NOT BE RESPONSIBLE FOR ANY MEDIATEK
+* SOFTWARE RELEASES MADE TO RECEIVER'S SPECIFICATION OR TO CONFORM TO A PARTICULAR
+* STANDARD OR OPEN FORUM. RECEIVER'S SOLE AND EXCLUSIVE REMEDY AND MEDIATEK'S ENTIRE AND
+* CUMULATIVE LIABILITY WITH RESPECT TO THE MEDIATEK SOFTWARE RELEASED HEREUNDER WILL BE,
+* AT MEDIATEK'S OPTION, TO REVISE OR REPLACE THE MEDIATEK SOFTWARE AT ISSUE,
+* OR REFUND ANY SOFTWARE LICENSE FEES OR SERVICE CHARGE PAID BY RECEIVER TO
+* MEDIATEK FOR SUCH MEDIATEK SOFTWARE AT ISSUE.
+*/
+
+#ifndef _ODM_MDTBO_H_
+#define _ODM_MDTBO_H_
+
+
+#ifdef MTK_GPT_SCHEME_SUPPORT
+#include <platform/partition.h>
+#else
+#include <mt_partition.h>
+#endif  // MTK_GPT_SCHEME_SUPPORT
+
+
+/******************************************************************************
+* Some platform, e.g. mt6755, defines the symbol BLK_SIZE rather than
+* PART_HDR_DATA_SIZE. in "partition.h".  If PART_HDR_DATA_SIZE is not defined,
+* define it here to avoid compilation error on those platforms.
+* TO DO: The interface (e.g. partition.h) should be common code.
+******************************************************************************/
+#ifndef PART_HDR_DATA_SIZE
+#define PART_HDR_DATA_SIZE      512
+#endif  // PART_HDR_DATA_SIZE
+
+#define ODM_MDTBO_HDR_SIZE      (512)
+#define ODM_MDTBO_HDR_PROLOG    (32)
+#define MAX_NUM_OF_ODM_MDTBO    ((ODM_MDTBO_HDR_SIZE - ODM_MDTBO_HDR_PROLOG) / 4)
+#define ODM_MDTBO_MAGIC         (0xdeaddead)
+#define ODM_MDTBO_VERSION       (2)
+
+
+/******************************************************************************
+* MDTBO: Multiple Device Tree Blob for Overlay
+******************************************************************************/
+typedef union {
+	struct {
+		unsigned int magic;             /* magic: PART_MAGIC = 0xdeaddead */
+		unsigned int dsize;             /* data size (not including this 512-byte header) */
+		unsigned int hdr_size;          /* header size */
+		unsigned int hdr_version;       /* header version: ODM_MDTBO_VERSION */
+		unsigned int num_of_dtbo;       /* number of dtbo */
+		unsigned int reserved[3];       /* reserved */
+		/* The data above this is the "header prolog". */
+		unsigned int dtbo_offset[MAX_NUM_OF_ODM_MDTBO];  /* offset of dtbo (not including this header) */
+	} info;
+	unsigned char data[ODM_MDTBO_HDR_SIZE];
+} mdtbo_hdr_t;
+
+
+/******************************************************************************
+* New DTBO partition format defined since Android P
+******************************************************************************/
+#define DT_TABLE_MAGIC 0xd7b7ab1e
+#define LARGE_DT_ENTRY_SIZE 0 //can be customized in case of built-in super large # of DT
+
+struct dt_table_header {
+	uint32_t magic;			// DT_TABLE_MAGIC
+	uint32_t total_size;		// includes dt_table_header + all dt_table_entry and all dtb/dtbo
+	uint32_t header_size;		// sizeof(dt_table_header)
+
+	uint32_t dt_entry_size;		// sizeof(dt_table_entry)
+	uint32_t dt_entry_count;	// number of dt_table_entry
+	uint32_t dt_entries_offset;	// offset to the first dt_table_entry from head of dt_table_header
+
+	uint32_t page_size;		// flash page size we assume
+	uint32_t version;		// DTBOage version, the current version is 0.
+					// The version will be incremented when the
+					// dt_table_header struct is updated.
+};
+
+struct dt_table_entry {
+	uint32_t dt_size;
+	uint32_t dt_offset;		// offset from head of dt_table_header
+
+	uint32_t id;			// use this field as index of CONFIG_BUILD_ARM_DTB_OVERLAY_IMAGE_NAMES
+	uint32_t rev;			// optional, must be zero if unused
+	uint32_t custom[4];		// optional, must be zero if unused
+};
+
+
+/******************************************************************************
+* NOTE: Customers need to implement their own customized_get_odm_mdtbo_index()
+*       function. If customized_get_odm_mdtbo_index() is not implemented, the
+*       value 0 will be used as the default dtbo index. Each customer can
+*       maintain their own implementation of customized_get_odm_mdtbo_index()
+*       in a separate source file as long as it can be linked.
+******************************************************************************/
+int customized_get_odm_mdtbo_index(void) __attribute__((weak));
+
+int get_odm_mdtbo_index(void);
+char *load_overlay_dtbo(char *part_name, unsigned int *size, uint64_t recovery_dtbo_offset);
+int get_dtbo_index(void);
+void set_dtbo_index(int dtbo_idx);
+
+#endif // _ODM_MDTBO_H_
+
+

+ 241 - 0
app/mt_boot/rules.mk

@@ -0,0 +1,241 @@
+LOCAL_DIR := $(GET_LOCAL_DIR)
+
+MT_BOOT_OBJ_DIR := $(BOOTLOADER_OUT)/build-$(PROJECT)/app/mt_boot
+
+ifeq ($(CUSTOM_SEC_CRYPTO_SUPPORT), yes)
+	OBJS += \
+		$(TO_ROOT)../../../mediatek/custom/common/security/fastboot/cust_auth.o
+endif
+
+ifeq ($(strip $(MTK_EMMC_SUPPORT)),yes)
+	FASTBOOT_PARALLEL_DOWNLOAD :=yes
+endif
+
+OBJS += \
+	$(LOCAL_DIR)/mt_boot.o \
+	$(LOCAL_DIR)/odm_mdtbo.o \
+	$(LOCAL_DIR)/decompressor.o\
+	$(LOCAL_DIR)/fastboot.o \
+	$(LOCAL_DIR)/iothread.o \
+	$(LOCAL_DIR)/sec_hrid.o \
+	$(LOCAL_DIR)/sec_socid.o \
+	$(LOCAL_DIR)/sys_commands.o \
+	$(LOCAL_DIR)/aee/mrdump_dummy.o \
+	$(LOCAL_DIR)/aee/mrdump_key_setup.o \
+	$(LOCAL_DIR)/blockheader.o \
+	$(LOCAL_DIR)/bootargs.o \
+	$(LOCAL_DIR)/fdt_op.o
+
+ifeq ($(FASTBOOT_PARALLEL_DOWNLOAD),yes)
+OBJS += \
+	$(LOCAL_DIR)/mtransfer/bulk_process.o \
+	$(LOCAL_DIR)/mtransfer/sparse_state_machine.o \
+	$(LOCAL_DIR)/mtransfer/transfer_parallel.o
+DEFINES += MTK_ULTRA_FLASH
+INCLUDES += -I$(LOCAL_DIR)/mtransfer
+ifeq ($(MTK_TLC_NAND_SUPPORT),yes)
+OBJS += \
+	$(LOCAL_DIR)/mtransfer/bulk_process_nand.o \
+	$(LOCAL_DIR)/mtransfer/sparse_state_machine_nand.o
+endif
+endif
+
+# DCONFIG
+ifeq ($(ARCH_HAVE_DCONFIG),yes)
+DEFINES += MTK_DCONFIG_SUPPORT
+endif
+
+# MRDUMP setting sanity check
+ifneq ($(ARCH_HAVE_MT_RAMDUMP),yes)
+ifneq ($(ARCH_HAVE_MT_RAMDUMP),no)
+ifneq ($(ARCH_HAVE_MT_RAMDUMP),)
+$(error Unknown ARCH_HAVE_MT_RAMDUMP setting.)
+endif
+endif
+endif
+
+ifneq ($(MTK_MRDUMP_ENABLE),dconfig)
+ifneq ($(MTK_MRDUMP_ENABLE),yes)
+ifneq ($(MTK_MRDUMP_ENABLE),no)
+ifneq ($(MTK_MRDUMP_ENABLE),)
+$(error Unknown MTK_MRDUMP_ENABLE setting.)
+endif
+endif
+endif
+endif
+
+# MRDUMP setting check
+build_mt_ramdump := no
+
+# user(default disable MRDUMP)
+ifeq ($(TARGET_BUILD_VARIANT),user)
+ifeq ($(MTK_MRDUMP_ENABLE),yes)
+build_mt_ramdump := yes
+endif
+ifeq ($(MTK_MRDUMP_ENABLE),dconfig)
+build_mt_ramdump := dconfig
+endif
+endif
+
+# eng(default enable MRDUMP)
+ifeq ($(TARGET_BUILD_VARIANT),eng)
+build_mt_ramdump := yes
+ifeq ($(MTK_MRDUMP_ENABLE),no)
+build_mt_ramdump := no
+endif
+endif
+
+# userdebug(default enable MRDUMP)
+ifeq ($(TARGET_BUILD_VARIANT),userdebug)
+build_mt_ramdump := yes
+ifeq ($(MTK_MRDUMP_ENABLE),no)
+build_mt_ramdump := no
+endif
+endif
+
+ifneq ($(build_mt_ramdump),no)
+# MRDUMP depend on AEE/MINI
+ifneq ($(KEDUMP_MINI),yes)
+$(info Disable mrdump support - AEE/mini disabled)
+build_mt_ramdump := no
+endif
+# MRDUMP show build warning if ARCH_HAVE_MT_RAMDUMP = no, and MTK_MRDUMP_ENABLE = yes
+ifeq ($(ARCH_HAVE_MT_RAMDUMP),no)
+$(info Disable mrdump support - architecture no support)
+build_mt_ramdump := no
+endif
+# MRDUMP doesn't support MLC NAND
+ifeq ($(MTK_MLC_NAND_SUPPORT),yes)
+$(info Disable mrdump support - mlc nand)
+build_mt_ramdump := no
+endif
+endif
+
+ifneq ($(build_mt_ramdump),no)
+
+ifeq ($(build_mt_ramdump),dconfig)
+DEFINES += MTK_MRDUMP_SUPPORT=2
+else
+DEFINES += MTK_MRDUMP_SUPPORT=1
+endif
+
+ifeq ($(strip $(MTK_MRDUMP_PARTITION_ENABLE)),yes)
+DEFINES += MRDUMP_PARTITION_ENABLE
+endif
+
+ifeq ($(strip $(MTK_MRDUMP_PARTITION_ENABLE)),debug)
+ifneq ($(TARGET_BUILD_VARIANT),user)
+DEFINES += MRDUMP_PARTITION_ENABLE
+endif
+endif
+
+OBJS += \
+	$(LOCAL_DIR)/aee/aee.o \
+	$(LOCAL_DIR)/aee/mrdump_datafs.o \
+	$(LOCAL_DIR)/aee/mrdump_dbgscript.o \
+	$(LOCAL_DIR)/aee/mrdump_dconfig.o \
+	$(LOCAL_DIR)/aee/mrdump_elf.o \
+	$(LOCAL_DIR)/aee/mrdump_mpart.o \
+	$(LOCAL_DIR)/aee/mrdump_null.o \
+	$(LOCAL_DIR)/aee/mrdump_rsvmem.o \
+	$(LOCAL_DIR)/aee/mrdump_sddev.o \
+	$(LOCAL_DIR)/aee/mrdump_usb.o \
+	$(LOCAL_DIR)/aee/mrdump_zip.o
+
+endif
+
+OBJS += $(LOCAL_DIR)/mt_hvc_call.o
+
+ifeq ($(KEDUMP_MINI), yes)
+OBJS += $(LOCAL_DIR)/aee/KEDump.o \
+	$(LOCAL_DIR)/aee/armmmu_translate.o \
+	$(LOCAL_DIR)/aee/platform_debug.o \
+	$(LOCAL_DIR)/aee/reboot_record.o \
+	$(LOCAL_DIR)/aee/mrdump_setup.o
+endif
+
+OBJS += \
+	$(LOCAL_DIR)/aee/ram_console.o
+
+SECRO_TYPE := GMP
+OBJS += \
+$(LOCAL_DIR)/dl_commands.o
+
+ifeq ($(MTK_SECURITY_SW_SUPPORT), yes)
+ifeq ($(MTK_SEC_FASTBOOT_UNLOCK_SUPPORT), yes)
+	OBJS += $(LOCAL_DIR)/sec_unlock.o
+endif
+endif
+
+ifeq ($(MTK_SMC_ID_MGMT), yes)
+DEFINES += MTK_SMC_ID_MGMT
+OBJS += $(LOCAL_DIR)/mt_secure_call.o
+endif
+
+ifeq ($(MTK_DIS_ATF_RAM_DUMP), yes)
+DEFINES += MTK_DIS_ATF_RAM_DUMP
+endif
+
+ifeq ($(BUILD_SEC_LIB),yes)
+#directories
+CRYPTO_DIR  := $(LOCAL_DIR)/crypto
+SEC_DIR   := $(LOCAL_DIR)/sec
+SEC_PLAT_DIR   := $(LOCAL_DIR)/platform
+EXPORT_INC_DIR   := $(LOCAL_DIR)/export_inc
+#source files te built
+CRYPTO_LOCAL_OBJS := $(patsubst $(CRYPTO_DIR)/%.c,$(CRYPTO_DIR)/%.o,$(wildcard $(CRYPTO_DIR)/*.c))
+SEC_LOCAL_OBJS  := $(patsubst $(SEC_DIR)/%.c,$(SEC_DIR)/%.o,$(wildcard $(SEC_DIR)/*.c))
+SEC_PLAT_LOCAL_OBJS  := $(patsubst $(SEC_PLAT_DIR)/%.c,$(SEC_PLAT_DIR)/%.o,$(wildcard $(SEC_PLAT_DIR)/*.c))
+#objet files to be archived(referenced by make/build.mk)
+CRYPTO_OBJS := $(patsubst $(CRYPTO_DIR)/%.c,$(MT_BOOT_OBJ_DIR)/crypto/%.o,$(wildcard $(CRYPTO_DIR)/*.c))
+SEC_OBJS  := $(patsubst $(SEC_DIR)/%.c,$(MT_BOOT_OBJ_DIR)/sec/%.o,$(wildcard $(SEC_DIR)/*.c))
+SEC_PLAT_OBJS  := $(patsubst $(SEC_PLAT_DIR)/%.c,$(MT_BOOT_OBJ_DIR)/platform/%.o,$(wildcard $(SEC_PLAT_DIR)/*.c))
+#include path and object file list for building
+INCLUDES += -I$(CRYPTO_DIR)/inc -I$(SEC_DIR)/inc -I$(SEC_PLAT_DIR) -I$(EXPORT_INC_DIR)
+OBJS += $(CRYPTO_LOCAL_OBJS) $(SEC_LOCAL_OBJS) $(SEC_PLAT_LOCAL_OBJS)
+endif
+
+ifeq ($(BUILD_DEVINFO_LIB),yes)
+DEVINFO_DIR   := $(LOCAL_DIR)/devinfo
+DEVINFO_LOCAL_OBJS  := $(patsubst $(DEVINFO_DIR)/%.c,$(DEVINFO_DIR)/%.o,$(wildcard $(DEVINFO_DIR)/*.c))
+DEVINFO_OBJS  := $(patsubst $(DEVINFO_DIR)/%.c,$(MT_BOOT_OBJ_DIR)/devinfo/%.o,$(wildcard $(DEVINFO_DIR)/*.c))
+INCLUDES += -I$(DEVINFO_DIR)
+OBJS += $(DEVINFO_LOCAL_OBJS)
+endif
+
+ifeq ($(BUILD_HW_CRYPTO_LIB),yes)
+HW_CRYPTO_DIR  := $(LOCAL_DIR)/hw_crypto
+INCLUDES += -I$(HW_CRYPTO_DIR)/inc
+HW_CRYPTO_LOCAL_OBJS := $(patsubst $(HW_CRYPTO_DIR)/%.c,$(HW_CRYPTO_DIR)/%.o,$(wildcard $(HW_CRYPTO_DIR)/*.c))
+HW_CRYPTO_OBJS := $(patsubst $(HW_CRYPTO_DIR)/%.c,$(MT_BOOT_OBJ_DIR)/hw_crypto/%.o,$(wildcard $(HW_CRYPTO_DIR)/*.c))
+OBJS += $(HW_CRYPTO_LOCAL_OBJS)
+endif
+
+ifeq ($(MTK_AB_OTA_UPDATER),yes)
+INCLUDES += -I$(LK_TOP_DIR)/platform/common/bootctrl
+endif
+
+INCLUDES += -I$(LK_TOP_DIR)/platform/common/RoT
+
+INCLUDES += -Iplatform/$(PLATFORM)/include/platform
+ifeq ($(CFG_MTK_WDT_COMMON), yes)
+INCLUDES += -I$(LK_TOP_DIR)/platform/common/wdt
+endif
+
+INCLUDES += -I$(LK_TOP_DIR)/dev/md_com
+
+ifeq ($(strip $(MTK_EMMC_SUPPORT)),yes)
+ifeq ($(strip $(MTK_MMC_COMBO_DRV)),yes)
+INCLUDES += -I$(LK_TOP_DIR)/platform/common/storage/mmc/inc
+else
+INCLUDES += -I$(LK_TOP_DIR)/platform/$(PLATFORM)/include
+endif
+endif
+
+ifeq ($(strip $(MNTL_SUPPORT)),yes)
+ifeq ($(strip $(MTK_MMC_COMBO_DRV)),yes)
+INCLUDES += -I$(LK_TOP_DIR)/platform/common/storage/mmc/inc
+else
+INCLUDES += -I$(LK_TOP_DIR)/platform/$(PLATFORM)/include
+endif
+endif

+ 69 - 0
app/mt_boot/sec_hrid.c

@@ -0,0 +1,69 @@
+/* Copyright Statement:
+*
+* This software/firmware and related documentation ("MediaTek Software") are
+* protected under relevant copyright laws. The information contained herein
+* is confidential and proprietary to MediaTek Inc. and/or its licensors.
+* Without the prior written permission of MediaTek inc. and/or its licensors,
+* any reproduction, modification, use or disclosure of MediaTek Software,
+* and information contained herein, in whole or in part, shall be strictly prohibited.
+*/
+/* MediaTek Inc. (C) 2015. All rights reserved.
+*
+* BY OPENING THIS FILE, RECEIVER HEREBY UNEQUIVOCALLY ACKNOWLEDGES AND AGREES
+* THAT THE SOFTWARE/FIRMWARE AND ITS DOCUMENTATIONS ("MEDIATEK SOFTWARE")
+* RECEIVED FROM MEDIATEK AND/OR ITS REPRESENTATIVES ARE PROVIDED TO RECEIVER ON
+* AN "AS-IS" BASIS ONLY. MEDIATEK EXPRESSLY DISCLAIMS ANY AND ALL WARRANTIES,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED WARRANTIES OF
+* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE OR NONINFRINGEMENT.
+* NEITHER DOES MEDIATEK PROVIDE ANY WARRANTY WHATSOEVER WITH RESPECT TO THE
+* SOFTWARE OF ANY THIRD PARTY WHICH MAY BE USED BY, INCORPORATED IN, OR
+* SUPPLIED WITH THE MEDIATEK SOFTWARE, AND RECEIVER AGREES TO LOOK ONLY TO SUCH
+* THIRD PARTY FOR ANY WARRANTY CLAIM RELATING THERETO. RECEIVER EXPRESSLY ACKNOWLEDGES
+* THAT IT IS RECEIVER'S SOLE RESPONSIBILITY TO OBTAIN FROM ANY THIRD PARTY ALL PROPER LICENSES
+* CONTAINED IN MEDIATEK SOFTWARE. MEDIATEK SHALL ALSO NOT BE RESPONSIBLE FOR ANY MEDIATEK
+* SOFTWARE RELEASES MADE TO RECEIVER'S SPECIFICATION OR TO CONFORM TO A PARTICULAR
+* STANDARD OR OPEN FORUM. RECEIVER'S SOLE AND EXCLUSIVE REMEDY AND MEDIATEK'S ENTIRE AND
+* CUMULATIVE LIABILITY WITH RESPECT TO THE MEDIATEK SOFTWARE RELEASED HEREUNDER WILL BE,
+* AT MEDIATEK'S OPTION, TO REVISE OR REPLACE THE MEDIATEK SOFTWARE AT ISSUE,
+* OR REFUND ANY SOFTWARE LICENSE FEES OR SERVICE CHARGE PAID BY RECEIVER TO
+* MEDIATEK FOR SUCH MEDIATEK SOFTWARE AT ISSUE.
+*/
+
+#include <platform/mt_typedefs.h>
+#include "sec_hrid.h"
+#include "sec_devinfo.h"
+
+u32 get_hrid_size(void)
+{
+    return HRID_SIZE;
+}
+
+u32 get_hrid(unsigned char *rid, unsigned char *rid_sz)
+{
+    u32 ret = E_SUCCESS;
+    u32 i, j;
+
+    if (rid_sz == NULL) {
+        return E_BUF_SIZE_ZERO_OR_NULL;
+    }
+
+    if (rid == NULL) {
+        return E_BUF_ZERO_OR_NULL;
+    }
+
+    if (*rid_sz < (HRID_SIZE * 4)) {
+        return E_BUF_NOT_ENOUGH;
+    }
+
+    for (i = 0; i < HRID_SIZE; i++) {
+        u32 reg_val = 0;
+        reg_val = get_devinfo_with_index(12 + i);
+        for (j = 0; j < 4; j++) {
+            *(rid + i * 4 + j) = (reg_val & (0xff << (8 * j))) >> (8 * j);
+        }
+    }
+
+    *rid_sz = HRID_SIZE * 4;
+
+    return ret;
+}

+ 43 - 0
app/mt_boot/sec_hrid.h

@@ -0,0 +1,43 @@
+/* Copyright Statement:
+*
+* This software/firmware and related documentation ("MediaTek Software") are
+* protected under relevant copyright laws. The information contained herein
+* is confidential and proprietary to MediaTek Inc. and/or its licensors.
+* Without the prior written permission of MediaTek inc. and/or its licensors,
+* any reproduction, modification, use or disclosure of MediaTek Software,
+* and information contained herein, in whole or in part, shall be strictly prohibited.
+*/
+/* MediaTek Inc. (C) 2015. All rights reserved.
+*
+* BY OPENING THIS FILE, RECEIVER HEREBY UNEQUIVOCALLY ACKNOWLEDGES AND AGREES
+* THAT THE SOFTWARE/FIRMWARE AND ITS DOCUMENTATIONS ("MEDIATEK SOFTWARE")
+* RECEIVED FROM MEDIATEK AND/OR ITS REPRESENTATIVES ARE PROVIDED TO RECEIVER ON
+* AN "AS-IS" BASIS ONLY. MEDIATEK EXPRESSLY DISCLAIMS ANY AND ALL WARRANTIES,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED WARRANTIES OF
+* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE OR NONINFRINGEMENT.
+* NEITHER DOES MEDIATEK PROVIDE ANY WARRANTY WHATSOEVER WITH RESPECT TO THE
+* SOFTWARE OF ANY THIRD PARTY WHICH MAY BE USED BY, INCORPORATED IN, OR
+* SUPPLIED WITH THE MEDIATEK SOFTWARE, AND RECEIVER AGREES TO LOOK ONLY TO SUCH
+* THIRD PARTY FOR ANY WARRANTY CLAIM RELATING THERETO. RECEIVER EXPRESSLY ACKNOWLEDGES
+* THAT IT IS RECEIVER'S SOLE RESPONSIBILITY TO OBTAIN FROM ANY THIRD PARTY ALL PROPER LICENSES
+* CONTAINED IN MEDIATEK SOFTWARE. MEDIATEK SHALL ALSO NOT BE RESPONSIBLE FOR ANY MEDIATEK
+* SOFTWARE RELEASES MADE TO RECEIVER'S SPECIFICATION OR TO CONFORM TO A PARTICULAR
+* STANDARD OR OPEN FORUM. RECEIVER'S SOLE AND EXCLUSIVE REMEDY AND MEDIATEK'S ENTIRE AND
+* CUMULATIVE LIABILITY WITH RESPECT TO THE MEDIATEK SOFTWARE RELEASED HEREUNDER WILL BE,
+* AT MEDIATEK'S OPTION, TO REVISE OR REPLACE THE MEDIATEK SOFTWARE AT ISSUE,
+* OR REFUND ANY SOFTWARE LICENSE FEES OR SERVICE CHARGE PAID BY RECEIVER TO
+* MEDIATEK FOR SUCH MEDIATEK SOFTWARE AT ISSUE.
+*/
+
+#ifndef __EFUSE_HRID_H__
+#define __EFUSE_HRID_H__
+
+#define E_SUCCESS               0x00000000
+#define E_BUF_NOT_ENOUGH        0x10000000
+#define E_BUF_ZERO_OR_NULL        0x20000000
+#define E_BUF_SIZE_ZERO_OR_NULL   0x40000000
+
+extern u32 get_hrid_size(void);
+extern u32 get_hrid(unsigned char *rid, unsigned char *rid_sz);
+
+#endif /* __EFUSE_HRID_H__ */

+ 130 - 0
app/mt_boot/sec_socid.c

@@ -0,0 +1,130 @@
+/* Copyright Statement:
+ *
+ * This software/firmware and related documentation ("MediaTek Software") are
+ * protected under relevant copyright laws. The information contained herein
+ * is confidential and proprietary to MediaTek Inc. and/or its licensors.
+ * Without the prior written permission of MediaTek inc. and/or its licensors,
+ * any reproduction, modification, use or disclosure of MediaTek Software,
+ * and information contained herein, in whole or in part, shall be strictly prohibited.
+ */
+/* MediaTek Inc. (C) 2019. All rights reserved.
+ *
+ * BY OPENING THIS FILE, RECEIVER HEREBY UNEQUIVOCALLY ACKNOWLEDGES AND AGREES
+ * THAT THE SOFTWARE/FIRMWARE AND ITS DOCUMENTATIONS ("MEDIATEK SOFTWARE")
+ * RECEIVED FROM MEDIATEK AND/OR ITS REPRESENTATIVES ARE PROVIDED TO RECEIVER ON
+ * AN "AS-IS" BASIS ONLY. MEDIATEK EXPRESSLY DISCLAIMS ANY AND ALL WARRANTIES,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE OR NONINFRINGEMENT.
+ * NEITHER DOES MEDIATEK PROVIDE ANY WARRANTY WHATSOEVER WITH RESPECT TO THE
+ * SOFTWARE OF ANY THIRD PARTY WHICH MAY BE USED BY, INCORPORATED IN, OR
+ * SUPPLIED WITH THE MEDIATEK SOFTWARE, AND RECEIVER AGREES TO LOOK ONLY TO SUCH
+ * THIRD PARTY FOR ANY WARRANTY CLAIM RELATING THERETO. RECEIVER EXPRESSLY ACKNOWLEDGES
+ * THAT IT IS RECEIVER'S SOLE RESPONSIBILITY TO OBTAIN FROM ANY THIRD PARTY ALL PROPER LICENSES
+ * CONTAINED IN MEDIATEK SOFTWARE. MEDIATEK SHALL ALSO NOT BE RESPONSIBLE FOR ANY MEDIATEK
+ * SOFTWARE RELEASES MADE TO RECEIVER'S SPECIFICATION OR TO CONFORM TO A PARTICULAR
+ * STANDARD OR OPEN FORUM. RECEIVER'S SOLE AND EXCLUSIVE REMEDY AND MEDIATEK'S ENTIRE AND
+ * CUMULATIVE LIABILITY WITH RESPECT TO THE MEDIATEK SOFTWARE RELEASED HEREUNDER WILL BE,
+ * AT MEDIATEK'S OPTION, TO REVISE OR REPLACE THE MEDIATEK SOFTWARE AT ISSUE,
+ * OR REFUND ANY SOFTWARE LICENSE FEES OR SERVICE CHARGE PAID BY RECEIVER TO
+ * MEDIATEK FOR SUCH MEDIATEK SOFTWARE AT ISSUE.
+ *
+ * The following software/firmware and/or related documentation ("MediaTek Software")
+ * have been modified by MediaTek Inc. All revisions are subject to any receiver\'s
+ * applicable license agreements with MediaTek Inc.
+ */
+
+
+#include <platform/mt_typedefs.h>
+#include "sec_unlock.h"
+#include "fastboot.h"
+#include <video.h>
+#include <string.h>
+#include <debug.h>
+#include <printf.h>
+#include <verified_boot_common.h>
+#include <verified_boot_error.h>
+#include <boot_mode.h>
+#include <pal_log.h>
+
+extern BOOT_ARGUMENT *g_boot_arg;
+
+static char int_to_str(char c)
+{
+	if (c <= 9)
+		return (c + 48);
+
+	return (c - 9) + 64;
+}
+
+uint32_t get_socid_chip(uint8_t *socid, uint32_t len)
+{
+	uint32_t ret = 0;
+
+#ifdef MTK_SEC_SOCID_SUPPORT
+
+	if (socid == NULL || g_boot_arg == NULL) {
+		ret = ERR_VB_INVALID_ADDR;
+		goto end;
+	}
+
+	memcpy(socid, g_boot_arg->socid, len);
+#else
+	if (socid == NULL) {
+		ret = ERR_VB_INVALID_ADDR;
+		goto end;
+	}
+
+	memset(socid, 0x0, len);
+#endif
+
+end:
+	return ret;
+}
+
+void fastboot_get_socid(const char *arg, void *data, unsigned sz)
+{
+#define MAX_SOCID_MSG_SZ (128)
+	uint32_t ret = 0;
+	uint32_t i, j;
+	char msg[MAX_SOCID_MSG_SZ] = {0};
+	char socid[SOC_ID_LEN] = {0};
+	char socid_first_half[SOC_ID_LEN + 1] = {0};
+	char socid_second_half[SOC_ID_LEN + 1] = {0};
+
+	ret = get_socid_chip((uint8_t *)socid, SOC_ID_LEN);
+	if (ret)
+		goto end;
+
+	/* separate 64 characters into two lines in order to fit fastboot
+	 * message length.
+	 */
+	for (i = 0, j = 0; i < SOC_ID_LEN && j < (SOC_ID_LEN / 2); i += 2, j++) {
+		socid_first_half[i] = int_to_str((socid[j] & 0xF0) >> 4);
+		socid_first_half[i + 1] = int_to_str(socid[j] & 0x0F);
+	}
+	socid_first_half[SOC_ID_LEN] = '\0';
+
+	for (i = 0, j = (SOC_ID_LEN / 2); i < SOC_ID_LEN && j < SOC_ID_LEN; i += 2, j++) {
+		socid_second_half[i] = int_to_str((socid[j] & 0xF0) >> 4);
+		socid_second_half[i + 1] = int_to_str(socid[j] & 0x0F);
+	}
+	socid_second_half[SOC_ID_LEN] = '\0';
+
+	fastboot_info("dump socid...");
+	fastboot_info(socid_first_half);
+	fastboot_info(socid_second_half);
+	fastboot_info("finish dump");
+
+end:
+	if (ret) {
+		if (snprintf(msg, MAX_SOCID_MSG_SZ, "\nget_socid failed - Err:0x%x\n", ret) >= 0) {
+			msg[MAX_SOCID_MSG_SZ - 1] = '\0';
+			fastboot_fail(msg);
+		} else {
+			fastboot_fail("unknown error\n");
+		}
+	} else
+		fastboot_okay("");
+	return;
+}
+

+ 524 - 0
app/mt_boot/sec_unlock.c

@@ -0,0 +1,524 @@
+/* Copyright Statement:
+*
+* This software/firmware and related documentation ("MediaTek Software") are
+* protected under relevant copyright laws. The information contained herein
+* is confidential and proprietary to MediaTek Inc. and/or its licensors.
+* Without the prior written permission of MediaTek inc. and/or its licensors,
+* any reproduction, modification, use or disclosure of MediaTek Software,
+* and information contained herein, in whole or in part, shall be strictly prohibited.
+*/
+/* MediaTek Inc. (C) 2015. All rights reserved.
+*
+* BY OPENING THIS FILE, RECEIVER HEREBY UNEQUIVOCALLY ACKNOWLEDGES AND AGREES
+* THAT THE SOFTWARE/FIRMWARE AND ITS DOCUMENTATIONS ("MEDIATEK SOFTWARE")
+* RECEIVED FROM MEDIATEK AND/OR ITS REPRESENTATIVES ARE PROVIDED TO RECEIVER ON
+* AN "AS-IS" BASIS ONLY. MEDIATEK EXPRESSLY DISCLAIMS ANY AND ALL WARRANTIES,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED WARRANTIES OF
+* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE OR NONINFRINGEMENT.
+* NEITHER DOES MEDIATEK PROVIDE ANY WARRANTY WHATSOEVER WITH RESPECT TO THE
+* SOFTWARE OF ANY THIRD PARTY WHICH MAY BE USED BY, INCORPORATED IN, OR
+* SUPPLIED WITH THE MEDIATEK SOFTWARE, AND RECEIVER AGREES TO LOOK ONLY TO SUCH
+* THIRD PARTY FOR ANY WARRANTY CLAIM RELATING THERETO. RECEIVER EXPRESSLY ACKNOWLEDGES
+* THAT IT IS RECEIVER'S SOLE RESPONSIBILITY TO OBTAIN FROM ANY THIRD PARTY ALL PROPER LICENSES
+* CONTAINED IN MEDIATEK SOFTWARE. MEDIATEK SHALL ALSO NOT BE RESPONSIBLE FOR ANY MEDIATEK
+* SOFTWARE RELEASES MADE TO RECEIVER'S SPECIFICATION OR TO CONFORM TO A PARTICULAR
+* STANDARD OR OPEN FORUM. RECEIVER'S SOLE AND EXCLUSIVE REMEDY AND MEDIATEK'S ENTIRE AND
+* CUMULATIVE LIABILITY WITH RESPECT TO THE MEDIATEK SOFTWARE RELEASED HEREUNDER WILL BE,
+* AT MEDIATEK'S OPTION, TO REVISE OR REPLACE THE MEDIATEK SOFTWARE AT ISSUE,
+* OR REFUND ANY SOFTWARE LICENSE FEES OR SERVICE CHARGE PAID BY RECEIVER TO
+* MEDIATEK FOR SUCH MEDIATEK SOFTWARE AT ISSUE.
+*/
+
+#include <platform/mt_typedefs.h>
+#include <platform/sec_status.h>
+#include <platform/mt_reg_base.h>
+#ifdef MTK_PARTITION_COMMON
+#include <env.h>
+#else
+#include <platform/env.h>
+#endif
+#include "sec_unlock.h"
+#include "fastboot.h"
+#include <target/cust_key.h>
+#include <platform/mt_gpt.h>
+#include <video.h>
+#include <string.h>
+#include <debug.h>
+#include <platform/mtk_key.h>
+#include <printf.h>
+#ifdef MTK_GPT_SCHEME_SUPPORT
+#include <platform/partition.h>
+#else
+#include <mt_partition.h>
+#endif
+#include <part_interface.h>
+#include <part_status.h>
+#include <verified_boot_common.h>
+
+#define UNLOCK_KEY_SIZE 32
+#define SERIAL_NUMBER_SIZE 16
+#define DEFAULT_SERIAL_NUM "0123456789ABCDEF"
+
+#define METADATA_PARTITION      "metadata"
+#define METADATA_PARTITION_ALT  "md_udc"
+#define CACHE_PARTITION         "cache"
+
+char fb_unlock_key_str[UNLOCK_KEY_SIZE+1] = {0};
+
+extern u32 get_devinfo_with_index(u32 index);
+extern int get_serial(u64 hwkey, u32 chipid, char ser[38]);
+extern void sec_get_serial_number_from_unlock_key(u8 *unlock_key, u32 unlock_key_len, u8 *cal_serial, u32 cal_serial_len);
+extern int sec_set_device_lock(int do_lock);
+extern int sec_query_device_lock(int *lock_state);
+
+static void fastboot_boot_menu(void)
+{
+	video_clean_screen();
+	video_set_cursor(video_get_rows()/2, 0);
+	video_printf("Select Boot Mode:\n[VOLUME_UP to select.  VOLUME_DOWN is OK.]\n\n");
+	video_printf("[Recovery    Mode]             \n");
+#ifdef MTK_FASTBOOT_SUPPORT
+	video_printf("[Fastboot    Mode]         <<==\n");
+#endif
+	video_printf("[Normal      Boot]             \n");
+#ifndef USER_BUILD
+	video_printf("[Normal      Boot +ftrace]    \n");
+	video_printf("[Normal      slub debug off]     \n");
+#endif
+	video_printf(" => FASTBOOT mode...\n");
+}
+
+static int fastboot_data_part_wipe()
+{
+	int ret = B_OK;
+	int set_env_ret = B_OK;
+	int err = PART_OK;
+
+	set_env_ret = set_env("unlock_erase", "start");
+	if (set_env_ret) {
+		dprintf(CRITICAL,"set_env fail\n");
+		return -1;
+	}
+
+	err = partition_erase("userdata");
+	if (err != PART_OK)
+		goto data_wipe_fail;
+
+	/* if userdata is wiped successfully but for some
+	 * reason md_udc is not wiped successfully, you'll
+	 * need to enter recovery mode to wipe data again.
+	 */
+	if (partition_exists(METADATA_PARTITION) == PART_OK) { /* for /metadata */
+		err = partition_erase(METADATA_PARTITION);
+		if (err != PART_OK)
+			goto data_wipe_fail;
+	}
+
+	if (partition_exists(METADATA_PARTITION_ALT) == PART_OK) { /* for /metadata */
+		err = partition_erase(METADATA_PARTITION_ALT);
+		if (err != PART_OK)
+			goto data_wipe_fail;
+	}
+
+	if (partition_exists(CACHE_PARTITION) == PART_OK) { /* for /cache */
+		err = partition_erase(CACHE_PARTITION);
+		if (err != PART_OK)
+			goto data_wipe_fail;
+	}
+
+	set_env_ret = set_env("unlock_erase", "pass");
+	if (set_env_ret) {
+		dprintf(CRITICAL,"set_env fail\n");
+		return -1;
+	}
+
+	return ret;
+
+data_wipe_fail:
+	dprintf(CRITICAL,"unlock_erase fail\n");
+
+	set_env_ret = set_env("unlock_erase", "fail");
+	if (set_env_ret)
+		dprintf(CRITICAL,"set_env fail\n");
+	return -1;
+}
+
+static int fastboot_get_unlock_perm(unsigned int *unlock_allowed)
+{
+	int ret = B_OK;
+	int part_ret = PART_OK;
+	unsigned long long size = 0;
+	unsigned long long unlock_allowed_flag_offset = 0;
+
+	part_ret = partition_exists("frp");
+	if (part_ret == PART_NOT_EXIST) {
+		dprintf(CRITICAL,"frp paritition does not exist\n");
+		/* backward compatible with KK, where frp partition does not exist */
+		*unlock_allowed = 1;
+		return B_OK;
+	}
+
+	/* get unlock enable flag address, which is inside frp partition */
+	size = partition_get_size_by_name("frp");
+	unlock_allowed_flag_offset = size - sizeof(unsigned int);
+
+	dprintf(CRITICAL,"frp paritition size: 0x%llx\n", size);
+	dprintf(CRITICAL,"unlock_allowed_flag_offset: 0x%llx\n", unlock_allowed_flag_offset);
+
+	ret = partition_read("frp", unlock_allowed_flag_offset, (u8 *)unlock_allowed, sizeof(unsigned int));
+	if (ret < 0) {
+		*unlock_allowed = 0;
+		return ret;
+	}
+
+	return B_OK;
+}
+
+#ifdef MTK_SEC_FASTBOOT_UNLOCK_KEY_SUPPORT
+static int fastboot_oem_key_chk(void)
+{
+#define SERIALNO_LEN    38
+	int ret = B_OK;
+	u32 chip_code = 0x0;
+	char serial_number[SERIALNO_LEN] = {0};
+	u64 key;
+	char cal_serial_number[SERIAL_NUMBER_SIZE+1] = {0};
+
+	/* Check for the unlock key */
+	if (UNLOCK_KEY_SIZE != strlen(fb_unlock_key_str)) {
+		//fastboot_fail("Unlock key length is incorrect!");
+		ret = ERR_UNLOCK_KEY_WRONG_LENGTH;
+		return ret;
+	}
+
+	/* Get the device serial number */
+	key = get_devinfo_with_index(13);
+	key = (key << 32) | get_devinfo_with_index(12);
+	chip_code = DRV_Reg32(APHW_CODE);
+	if (key != 0)
+		get_serial(key, chip_code, serial_number);
+	else
+		memcpy(serial_number, DEFAULT_SERIAL_NUM, SERIAL_NUMBER_SIZE);
+
+	/* Calculate the serial number from the unlock key */
+	sec_get_serial_number_from_unlock_key((u8 *)fb_unlock_key_str, UNLOCK_KEY_SIZE, (u8 *)cal_serial_number, SERIAL_NUMBER_SIZE);
+
+	/* Compare the results */
+	if (0 != memcmp(serial_number, cal_serial_number, SERIAL_NUMBER_SIZE)) {
+		//fastboot_fail("Unlock key code is incorrect!");
+		ret = ERR_UNLOCK_WRONG_KEY_CODE;
+		return ret;
+	}
+
+	return ret;
+}
+#endif
+
+static int fastboot_oem_unlock_chk(void)
+{
+	int ret = B_OK;
+
+#ifdef MTK_SEC_FASTBOOT_UNLOCK_KEY_SUPPORT
+	if (B_OK != (ret = fastboot_oem_key_chk())) {
+		goto _fail;
+	}
+#endif
+
+	/* Do format operation of data partition */
+	if (B_OK != (ret = fastboot_data_part_wipe())) {
+		//fastboot_fail("Data partition wipe failed!");
+		goto _fail;
+	}
+
+	/* Set unlock done flag */
+	ret = sec_set_device_lock(0);
+
+_fail:
+	return ret;
+}
+
+static int fastboot_oem_lock_chk()
+{
+#define TRY_LOCK 1
+	int ret = B_OK;
+	int inFactory = 0;
+	int wipe_userdata = 0;
+
+	if (B_OK != (ret = sec_boot_check(TRY_LOCK))) {
+		goto _image_verify_fail;
+	}
+
+	ret = sec_is_in_factory(&inFactory);
+	if (ret)
+		return ret;
+
+	/* tool connection in preloader is not disabled by default */
+	/* and device must be locked before product delivery */
+	/* at this time, don't wipe userdata to accelerate boot time */
+	wipe_userdata = inFactory ? 0 : 1;
+	if (wipe_userdata) {
+		if (B_OK != (ret = fastboot_data_part_wipe())) {
+			//fastboot_fail("Data partition wipe failed!");
+			goto _erase_data_fail;
+		}
+	}
+
+	/* Set lock done flag */
+	ret = sec_set_device_lock(1);
+
+_image_verify_fail:
+_erase_data_fail:
+	return ret;
+}
+
+
+void unlock_warranty(void)
+{
+	video_clean_screen();
+	video_set_cursor(video_get_rows()/2, 0);
+	video_printf("Unlock bootloader?\n\n");
+	video_printf("If you unlock the bootloader,you will be able to install custom operating\n");
+	video_printf("system software on this phone.\n\n");
+
+	video_printf("A custom OS is not subject to the same testing as the original OS, and can\n");
+	video_printf("cause your phone and installed applications to stop working properly.\n\n");
+
+	video_printf("To prevent unauthorized access to your personal data,unlocking the bootloader\n");
+	video_printf("will also delete all personal data from your phone(a \"factory data reset\").\n\n");
+
+	video_printf("Press the Volume UP/Down buttons to select Yes or No. \n\n");
+	video_printf("Yes (Volume UP):Unlock(may void warranty).\n\n");
+	video_printf("No (Volume Down):Do not unlock bootloader.\n\n");
+
+}
+
+void lock_warranty(void)
+{
+	video_clean_screen();
+	video_set_cursor(video_get_rows()/2, 0);
+	video_printf("lock bootloader?\n\n");
+	video_printf("If you lock the bootloader,you will need to install official operating\n");
+	video_printf("system software on this phone.\n\n");
+
+
+	video_printf("To prevent unauthorized access to your personal data,locking the bootloader\n");
+	video_printf("will also delete all personal data from your phone(a \"factory data reset\").\n\n");
+
+	video_printf("Press the Volume UP/Down buttons to select Yes or No. \n\n");
+	video_printf("Yes (Volume UP):Lock bootloader.\n\n");
+	video_printf("No (Volume Down):Do not lock bootloader.\n\n");
+}
+
+void fastboot_get_unlock_ability(const char *arg, void *data, unsigned sz)
+{
+#define UNLOCK_CAP_RESP_MAX_SIZE 64
+	int ret = B_OK;
+	unsigned int unlock_allowed = 0;
+	char msg[UNLOCK_CAP_RESP_MAX_SIZE] = {0};
+	const char *unknown_fastboot_error_msg = "Unknown error\n";
+
+	ret = fastboot_get_unlock_perm(&unlock_allowed);
+	if (ret != B_OK) {
+		if (snprintf(msg, UNLOCK_CAP_RESP_MAX_SIZE, "\nFailed to get unlock permission - Err:0x%x \n", ret) >= 0) {
+			msg[UNLOCK_CAP_RESP_MAX_SIZE - 1] = '\0'; /* prevent msg from not being ended with '\0'*/
+			fastboot_fail(msg);
+		} else {
+			fastboot_fail(unknown_fastboot_error_msg);
+		}
+	} else {
+		if (snprintf(msg, UNLOCK_CAP_RESP_MAX_SIZE, "unlock_ability = %d", unlock_allowed) >= 0) {
+			msg[UNLOCK_CAP_RESP_MAX_SIZE - 1] = '\0'; /* prevent msg from not being ended with '\0'*/
+			fastboot_info(msg);
+			fastboot_okay("");
+		} else {
+			fastboot_fail(unknown_fastboot_error_msg);
+		}
+	}
+
+	return;
+}
+
+void fastboot_oem_key(const char *arg, void *data, unsigned sz)
+{
+	int key_length;
+	key_length = strlen(arg + 1);
+	if (key_length != UNLOCK_KEY_SIZE) {
+		fastboot_fail("argument size is wrong\n");
+	} else {
+		strncpy(fb_unlock_key_str, arg + 1, sizeof(fb_unlock_key_str));
+		fb_unlock_key_str[sizeof(fb_unlock_key_str) - 1] = '\0';
+		dprintf(INFO,"key is '%s' and length is %d\n",fb_unlock_key_str,key_length);
+		fastboot_okay("");
+	}
+
+	return;
+}
+
+void fastboot_oem_query_lock_state(const char *arg, void *data, unsigned sz)
+{
+#define LKS_RESP_MAX_SIZE 64
+	int ret = B_OK;
+	int lock_state;
+	char msg[LKS_RESP_MAX_SIZE] = {0};
+	const char *unknown_fastboot_error_msg = "Unknown error\n";
+
+	ret = sec_query_device_lock(&lock_state);
+	if (ret != B_OK) {
+		if (snprintf(msg, LKS_RESP_MAX_SIZE, "cannot get lks (ret = 0x%x)", ret) >= 0) {
+			msg[LKS_RESP_MAX_SIZE - 1] = '\0';
+			fastboot_fail(msg);
+		} else {
+			fastboot_fail(unknown_fastboot_error_msg);
+		}
+	} else {
+		if (snprintf(msg, LKS_RESP_MAX_SIZE, "lks = %d", lock_state) >= 0) {
+			msg[LKS_RESP_MAX_SIZE - 1] = '\0';
+			fastboot_info(msg);
+			fastboot_okay("");
+		} else {
+			fastboot_fail(unknown_fastboot_error_msg);
+		}
+	}
+}
+
+void fastboot_oem_unlock(const char *arg, void *data, unsigned sz)
+{
+#define MAX_FASTBOOT_MSG_SZ (128)
+	int ret = B_OK;
+	char msg[MAX_FASTBOOT_MSG_SZ] = {0};
+	const char *fastboot_error_msg = NULL;
+	const char *unknown_fastboot_error_msg = "Unknown error\n";
+	unsigned int unlock_allowed = 0;
+
+	unlock_warranty();
+
+	while (1) {
+		if (mtk_detect_key(MT65XX_MENU_SELECT_KEY)) { //VOL_UP
+			fastboot_info("Start unlock flow\n");
+			//Invoke security check after confirming "yes" by user
+			ret = fastboot_get_unlock_perm(&unlock_allowed);
+			if (ret != B_OK) {
+				if (snprintf(msg, MAX_FASTBOOT_MSG_SZ, "\nFailed to get unlock permission - Err:0x%x\n", ret) >= 0) {
+					msg[MAX_FASTBOOT_MSG_SZ - 1] = '\0';
+					fastboot_error_msg = msg;
+				} else {
+					fastboot_error_msg = unknown_fastboot_error_msg;
+				}
+				video_printf("Unlock failed...return to fastboot in 3s\n");
+				mdelay(3000);
+				fastboot_boot_menu();
+				fastboot_fail(fastboot_error_msg);
+				break;
+			}
+
+			dprintf(CRITICAL,"unlock_allowed = 0x%x\n", unlock_allowed);
+
+			if (!unlock_allowed) {
+				if (snprintf(msg, MAX_FASTBOOT_MSG_SZ, "\nUnlock operation is not allowed\n") >= 0) {
+					msg[MAX_FASTBOOT_MSG_SZ - 1] = '\0';
+					fastboot_error_msg = msg;
+				} else {
+					fastboot_error_msg = unknown_fastboot_error_msg;
+				}
+				video_printf("Unlock failed...return to fastboot in 3s\n");
+				mdelay(3000);
+				fastboot_boot_menu();
+				fastboot_fail(fastboot_error_msg);
+				break;
+			}
+
+			ret = fastboot_oem_unlock_chk();
+			if (ret != B_OK) {
+				if (snprintf(msg, MAX_FASTBOOT_MSG_SZ, "\nUnlock failed - Err:0x%x\n", ret) >= 0) {
+					msg[MAX_FASTBOOT_MSG_SZ - 1] = '\0';
+					fastboot_error_msg = msg;
+				} else {
+					fastboot_error_msg = unknown_fastboot_error_msg;
+				}
+				video_printf("Unlock failed...return to fastboot in 3s\n");
+				mdelay(3000);
+				fastboot_boot_menu();
+				fastboot_fail(fastboot_error_msg);
+			} else {
+				video_printf("Unlock Pass...return to fastboot in 3s\n");
+				mdelay(3000);
+				fastboot_boot_menu();
+				fastboot_okay("");
+			}
+			break;
+		} else if (mtk_detect_key(MT65XX_MENU_OK_KEY)) { //VOL_DOWN
+			video_printf("return to fastboot in 3s\n");
+			mdelay(3000);
+			fastboot_boot_menu();
+			fastboot_okay("");
+			break;
+		} else {
+			//If we press other keys, discard it.
+		}
+	}
+
+	return;
+}
+
+void fastboot_oem_lock(const char *arg, void *data, unsigned sz)
+{
+#define MAX_FASTBOOT_MSG_SZ (128)
+	int ret = B_OK;
+	const char default_msg[] = "\nUnknown error!\n";
+	char print_msg[MAX_FASTBOOT_MSG_SZ] = {0};
+	const char *msg = NULL;
+	int inFactory = 0;
+	int requireConfirmation = 0;
+
+	ret = sec_is_in_factory(&inFactory);
+	if (ret) {
+		msg = default_msg;
+		if (snprintf(print_msg, MAX_FASTBOOT_MSG_SZ, "\nlock failed - Err:0x%x \n", ret) > 0) {
+			msg = print_msg;
+		}
+		video_printf("lock failed...return to fastboot in 3s\n");
+		mdelay(3000);
+		fastboot_boot_menu();
+		fastboot_fail(msg);
+		return;
+	}
+
+	requireConfirmation = inFactory ? 0 : 1;
+
+	lock_warranty();
+
+	while (1) {
+		if (mtk_detect_key(MT65XX_MENU_SELECT_KEY) || !requireConfirmation) { //VOL_UP
+			fastboot_info("Start lock flow\n");
+			//Invoke security check after confiming "yes" by user
+			ret = fastboot_oem_lock_chk();
+			if (ret != B_OK) {
+				msg = default_msg;
+				if (snprintf(print_msg, MAX_FASTBOOT_MSG_SZ, "\nlock failed - Err:0x%x \n", ret) > 0) {
+					msg = print_msg;
+				}
+				video_printf("lock failed...return to fastboot in 3s\n");
+				mdelay(3000);
+				fastboot_boot_menu();
+				fastboot_fail(msg);
+			} else {
+				video_printf("lock Pass...return to fastboot in 3s\n");
+				mdelay(3000);
+				fastboot_boot_menu();
+				fastboot_okay("");
+			}
+			break;
+		} else if (mtk_detect_key(MT65XX_MENU_OK_KEY)) { //VOL_DOWN
+			video_printf("return to fastboot in 3s\n");
+			mdelay(3000);
+			fastboot_boot_menu();
+			fastboot_okay("");
+			break;
+		} else {
+			//If we press other keys, discard it.
+		}
+	}
+
+	return;
+}
+

+ 44 - 0
app/mt_boot/sec_unlock.h

@@ -0,0 +1,44 @@
+/* Copyright Statement:
+*
+* This software/firmware and related documentation ("MediaTek Software") are
+* protected under relevant copyright laws. The information contained herein
+* is confidential and proprietary to MediaTek Inc. and/or its licensors.
+* Without the prior written permission of MediaTek inc. and/or its licensors,
+* any reproduction, modification, use or disclosure of MediaTek Software,
+* and information contained herein, in whole or in part, shall be strictly prohibited.
+*/
+/* MediaTek Inc. (C) 2017. All rights reserved.
+*
+* BY OPENING THIS FILE, RECEIVER HEREBY UNEQUIVOCALLY ACKNOWLEDGES AND AGREES
+* THAT THE SOFTWARE/FIRMWARE AND ITS DOCUMENTATIONS ("MEDIATEK SOFTWARE")
+* RECEIVED FROM MEDIATEK AND/OR ITS REPRESENTATIVES ARE PROVIDED TO RECEIVER ON
+* AN "AS-IS" BASIS ONLY. MEDIATEK EXPRESSLY DISCLAIMS ANY AND ALL WARRANTIES,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED WARRANTIES OF
+* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE OR NONINFRINGEMENT.
+* NEITHER DOES MEDIATEK PROVIDE ANY WARRANTY WHATSOEVER WITH RESPECT TO THE
+* SOFTWARE OF ANY THIRD PARTY WHICH MAY BE USED BY, INCORPORATED IN, OR
+* SUPPLIED WITH THE MEDIATEK SOFTWARE, AND RECEIVER AGREES TO LOOK ONLY TO SUCH
+* THIRD PARTY FOR ANY WARRANTY CLAIM RELATING THERETO. RECEIVER EXPRESSLY ACKNOWLEDGES
+* THAT IT IS RECEIVER'S SOLE RESPONSIBILITY TO OBTAIN FROM ANY THIRD PARTY ALL PROPER LICENSES
+* CONTAINED IN MEDIATEK SOFTWARE. MEDIATEK SHALL ALSO NOT BE RESPONSIBLE FOR ANY MEDIATEK
+* SOFTWARE RELEASES MADE TO RECEIVER'S SPECIFICATION OR TO CONFORM TO A PARTICULAR
+* STANDARD OR OPEN FORUM. RECEIVER'S SOLE AND EXCLUSIVE REMEDY AND MEDIATEK'S ENTIRE AND
+* CUMULATIVE LIABILITY WITH RESPECT TO THE MEDIATEK SOFTWARE RELEASED HEREUNDER WILL BE,
+* AT MEDIATEK'S OPTION, TO REVISE OR REPLACE THE MEDIATEK SOFTWARE AT ISSUE,
+* OR REFUND ANY SOFTWARE LICENSE FEES OR SERVICE CHARGE PAID BY RECEIVER TO
+* MEDIATEK FOR SUCH MEDIATEK SOFTWARE AT ISSUE.
+*
+* The following software/firmware and/or related documentation ("MediaTek Software")
+* have been modified by MediaTek Inc. All revisions are subject to any receiver\'s
+* applicable license agreements with MediaTek Inc.
+*/
+
+#ifndef _SEC_UNLOCK_H_
+#define _SEC_UNLOCK_H_
+
+void fastboot_oem_unlock(const char *arg, void *data, unsigned sz);
+void fastboot_oem_lock(const char *arg, void *data, unsigned sz);
+void fastboot_get_unlock_ability(const char *arg, void *data, unsigned sz);
+
+#endif
+

+ 48 - 0
app/mt_boot/sparse_format.h

@@ -0,0 +1,48 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+typedef struct sparse_header {
+  uint32_t  magic;		/* 0xed26ff3a */
+  uint16_t	major_version;	/* (0x1) - reject images with higher major versions */
+  uint16_t	minor_version;	/* (0x0) - allow images with higer minor versions */
+  uint16_t	file_hdr_sz;	/* 28 bytes for first revision of the file format */
+  uint16_t	chunk_hdr_sz;	/* 12 bytes for first revision of the file format */
+  uint32_t	blk_sz;		/* block size in bytes, must be a multiple of 4 (4096) */
+  uint32_t	total_blks;	/* total blocks in the non-sparse output image */
+  uint32_t	total_chunks;	/* total chunks in the sparse input image */
+  uint32_t	image_checksum; /* CRC32 checksum of the original data, counting "don't care" */
+				/* as 0. Standard 802.3 polynomial, use a Public Domain */
+				/* table implementation */
+} sparse_header_t;
+
+#define SPARSE_HEADER_MAGIC	0xed26ff3a
+
+#define CHUNK_TYPE_RAW		0xCAC1
+#define CHUNK_TYPE_FILL		0xCAC2
+#define CHUNK_TYPE_DONT_CARE	0xCAC3
+#define CHUNK_TYPE_CRC		0xCAC4
+
+typedef struct chunk_header {
+  uint16_t	chunk_type;	/* 0xCAC1 -> raw; 0xCAC2 -> fill; 0xCAC3 -> don't care */
+  uint16_t	reserved1;
+  uint32_t	chunk_sz;	/* in blocks in output image */
+  uint32_t	total_sz;	/* in bytes of chunk input file including chunk header and data */
+} chunk_header_t;
+
+/* Following a Raw or Fill chunk is data.  For a Raw chunk, it's the data in chunk_sz * blk_sz.
+ *  For a Fill chunk, it's 4 bytes of the fill data.
+ */
+

+ 846 - 0
app/mt_boot/sys_commands.c

@@ -0,0 +1,846 @@
+/* Copyright Statement:
+*
+* This software/firmware and related documentation ("MediaTek Software") are
+* protected under relevant copyright laws. The information contained herein
+* is confidential and proprietary to MediaTek Inc. and/or its licensors.
+* Without the prior written permission of MediaTek inc. and/or its licensors,
+* any reproduction, modification, use or disclosure of MediaTek Software,
+* and information contained herein, in whole or in part, shall be strictly prohibited.
+*/
+/* MediaTek Inc. (C) 2015. All rights reserved.
+*
+* BY OPENING THIS FILE, RECEIVER HEREBY UNEQUIVOCALLY ACKNOWLEDGES AND AGREES
+* THAT THE SOFTWARE/FIRMWARE AND ITS DOCUMENTATIONS ("MEDIATEK SOFTWARE")
+* RECEIVED FROM MEDIATEK AND/OR ITS REPRESENTATIVES ARE PROVIDED TO RECEIVER ON
+* AN "AS-IS" BASIS ONLY. MEDIATEK EXPRESSLY DISCLAIMS ANY AND ALL WARRANTIES,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED WARRANTIES OF
+* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE OR NONINFRINGEMENT.
+* NEITHER DOES MEDIATEK PROVIDE ANY WARRANTY WHATSOEVER WITH RESPECT TO THE
+* SOFTWARE OF ANY THIRD PARTY WHICH MAY BE USED BY, INCORPORATED IN, OR
+* SUPPLIED WITH THE MEDIATEK SOFTWARE, AND RECEIVER AGREES TO LOOK ONLY TO SUCH
+* THIRD PARTY FOR ANY WARRANTY CLAIM RELATING THERETO. RECEIVER EXPRESSLY ACKNOWLEDGES
+* THAT IT IS RECEIVER'S SOLE RESPONSIBILITY TO OBTAIN FROM ANY THIRD PARTY ALL PROPER LICENSES
+* CONTAINED IN MEDIATEK SOFTWARE. MEDIATEK SHALL ALSO NOT BE RESPONSIBLE FOR ANY MEDIATEK
+* SOFTWARE RELEASES MADE TO RECEIVER'S SPECIFICATION OR TO CONFORM TO A PARTICULAR
+* STANDARD OR OPEN FORUM. RECEIVER'S SOLE AND EXCLUSIVE REMEDY AND MEDIATEK'S ENTIRE AND
+* CUMULATIVE LIABILITY WITH RESPECT TO THE MEDIATEK SOFTWARE RELEASED HEREUNDER WILL BE,
+* AT MEDIATEK'S OPTION, TO REVISE OR REPLACE THE MEDIATEK SOFTWARE AT ISSUE,
+* OR REFUND ANY SOFTWARE LICENSE FEES OR SERVICE CHARGE PAID BY RECEIVER TO
+* MEDIATEK FOR SUCH MEDIATEK SOFTWARE AT ISSUE.
+*/
+
+#include <app.h>
+#include <debug.h>
+#include <arch/arm.h>
+#include <arch/arm/mmu.h>
+#include <dev/udc.h>
+#include <dev/mrdump.h>
+#include <string.h>
+#include <stdlib.h>
+#include <kernel/thread.h>
+#include <kernel/timer.h>
+#include <arch/ops.h>
+
+#include <target.h>
+#include <platform.h>
+
+#include <platform/mt_reg_base.h>
+#include <platform/boot_mode.h>
+#ifdef CFG_MTK_WDT_COMMON
+#include <mtk_wdt.h>
+#else
+#include <platform/mtk_wdt.h>   // for mtk_wdt_disable()
+#endif
+#include <platform/mt_rtc.h>
+#include <bootimg.h>
+#ifdef MTK_GPT_SCHEME_SUPPORT
+#include <platform/partition.h>
+#else
+#include <mt_partition.h>
+#endif
+#include <platform/mt_gpt.h>
+#include <platform/disp_drv_platform.h>
+#include <platform/mt_disp_drv.h>
+#include "fastboot.h"
+#include "sys_commands.h"
+#include <mt_scp_if.h>
+#include <log_store_lk.h>
+#ifdef MTK_PARTITION_COMMON
+#include <env.h>
+#else
+#include <platform/env.h>
+#endif
+#include <boot_info.h>
+
+#include "aee/aee.h"
+#include <recovery.h>
+
+/*** FIXME!!! #include <disp_drv.h>           // for DISP_IsLcmFound(), DISP_GetVRamSize() ***/
+BOOL DISP_IsLcmFound(void);
+UINT32 DISP_GetVRamSize(void);
+
+
+extern struct fastboot_var *varlist;
+extern struct fastboot_cmd *cmdlist;
+extern int boot_linux_from_storage(void);
+extern const char *mt_disp_get_lcm_id(void);
+extern void boot_linux(void *kernel, unsigned *tags, char *cmdline,
+		       unsigned machtype, void *ramdisk, unsigned ramdisk_sz);
+extern unsigned int memory_size();
+extern void custom_port_in_kernel(BOOTMODE boot_mode, char *command);
+#ifdef MTK_OFF_MODE_CHARGE_SUPPORT
+extern void set_off_mode_charge_status(int enable);
+extern bool get_off_mode_charge_status(void);
+#endif
+
+#ifdef MTK_AB_OTA_UPDATER
+#include "bootctrl.h"
+extern int set_active_slot(const char *suffix);
+#endif
+
+#define MODULE_NAME "FASTBOOT"
+#define MAX_RSP_SIZE 64
+
+
+extern BOOTMODE g_boot_mode;
+extern timer_t wdt_timer;
+extern unsigned int _heap_end;
+
+
+int has_set_p2u = 0; //0-unset; 1-on; 2-off
+#ifdef MTK_TC7_COMMON_DEVICE_INTERFACE
+static unsigned char *head_of_adb_cmdline;
+static unsigned char adb_cmdline_appended;
+#endif
+
+#ifdef MTK_MRDUMP_SUPPORT
+int after_usb_dump = 0;
+#endif
+
+// FIXME!!! The following function declaration should not exist, and appropriate
+//          header files instead should be included.
+extern bool cmdline_append(const char *append_string);
+extern bool cmdline_overwrite(const char *overwrite_string);
+extern char *cmdline_get(void);
+
+extern void set_uart_log_flag(bool enable);
+
+void cmd_overwirte_cmdline(const char *arg, void *data, unsigned sz)
+{
+	const char *new_kernel_cmd_line = arg;
+	if (cmdline_overwrite(new_kernel_cmd_line) == false) {
+		dprintf(CRITICAL, "[FASTBOOT] Input cmdline length is too long!");
+		fastboot_fail("cmdline length is too long");
+	}
+	dprintf(INFO, "[FASTBOOT] New command line is %s\n", (char *)cmdline_get());
+	fastboot_okay("");
+}
+
+
+void cmd_oem_append_cmdline(const char *arg, void *data, unsigned sz)
+{
+	dprintf(INFO, "APPEND KERNEL CMDLINE\n");
+	fastboot_info("APPEND KERNEL CMDLINE\n");
+	if (cmdline_append(arg) == false) {
+		dprintf(CRITICAL, "[FASTBOOT] Input cmdline length is too long!");
+		fastboot_fail("cmdline length is too long");
+		return;
+	}
+	dprintf(INFO, "[FASTBOOT] New command line:%s\n", (char *)cmdline_get());
+	fastboot_okay("");
+	return;
+}
+
+#ifdef MTK_MRDUMP_SUPPORT
+
+void cmd_oem_mrdump(const char *arg, void *data, unsigned sz)
+{
+	after_usb_dump = 1;
+	if (0 == strncmp(arg, " fullreset", 10)) {
+		dprintf(INFO, "[FASTBOOT] mrdump reset!\n");
+		fastboot_okay("");
+		mrdump_reboot();
+	}
+
+	dprintf(INFO, "[FASTBOOT] MRDUMP USB Dump Go!\n");
+	fastboot_okay("");
+	mrdump_run2();
+
+#ifdef SUPPORT_U3
+	fastboot_reset_usb();
+#endif
+
+	return;
+}
+
+void cmd_oem_mrdump_outdev(const char *arg, void *data, unsigned int sz)
+{
+	const char *ptr = arg + 1;
+	if (mrdump_set_output_device(ptr) != MRDUMP_DEV_UNKNOWN) {
+		fastboot_okay("");
+	}
+	else {
+		fastboot_fail("MRDUMP output device setting failed.");
+	}
+}
+
+void cmd_oem_mrdump_fallocate(const char *arg, void *data, unsigned int sz)
+{
+	char response[MAX_RSP_SIZE];
+	const char *ptr = arg + 1;
+	bool ret = 1;
+
+	int size_m = atoi(ptr);
+
+	if (size_m < 0)
+		size_m = 0;
+
+	switch (size_m) {
+	case 0:
+		ret = mrdump_set_env("mrdump_allocate_size", "0");
+		fastboot_info("mrdump_allocate_size -> 0");
+		break;
+	case 1:
+		ret = mrdump_set_env("mrdump_allocate_size", "halfmem");
+		fastboot_info("mrdump_allocate_size -> halfmem");
+		break;
+	case 2:
+		ret = mrdump_set_env("mrdump_allocate_size", "fullmem");
+		fastboot_info("mrdump_allocate_size -> fullmem");
+		break;
+	default:
+		if (size_m >= 256)
+			ret = mrdump_set_env("mrdump_allocate_size", (char *)ptr);
+		int n = snprintf(response, MAX_RSP_SIZE,
+			 "mrdump_allocate_size -> :%s", ptr);
+		if (n < 0) {
+			strncpy(response, "unknown error", sizeof(response) - 1);
+			response[sizeof(response) - 1] = '\0';
+		}
+		fastboot_info(response);
+		break;
+	}
+
+	if (ret == 0)
+		fastboot_okay("");
+	else
+		fastboot_fail("mrdump_allocate_size not set.");
+}
+
+void cmd_oem_mrdump_chkimg(const char *arg, void *data, unsigned int sz)
+{
+	int status = mrdump_check_enable();
+
+	switch (status) {
+		case MRDUMP_SUCCESS_ENABLE:
+			fastboot_info("mrdump successfully enabled");
+			break;
+		case MRDUMP_ALWAYS_ENABLE:
+			fastboot_info("mrdump always enabled");
+			break;
+		case MRDUMP_ALWAYS_DISABLE:
+			fastboot_info("mrdump always disabled");
+			break;
+		case MRDUMP_NO_SOCID_FROM_CHIP:
+			fastboot_info("unable to get socid from chip");
+			break;
+		case MRDUMP_SEC_IMG_AUTH_INIT_ERROR:
+			fastboot_info("mrdump dconfig image auth init failed");
+			break;
+		case MRDUMP_DCONFIG_MALLOC_ERROR:
+			fastboot_info("mrdump dconfig not enough memory");
+			break;
+		case MRDUMP_MBOOT_LOAD_PART_ERROR:
+			fastboot_info("mrdump dconfig partition_read failed");
+			break;
+		case MRDUMP_DCONFIG_IMG_VERIFY_ERROR:
+			fastboot_info("mrdump dconfig image verify failed");
+			break;
+		case MRDUMP_DCONFIG_SOCID_CERT_ERROR:
+			fastboot_info("unable to get socid from certed image");
+			break;
+		case MRDUMP_DCNFIG_SOCID_MISMATCH:
+			fastboot_info("socid mismatched");
+			break;
+		case MRDUMP_NOT_VALID_IMG:
+			fastboot_info("not a valid mrdump enabled image");
+			break;
+		default:
+			fastboot_info("unknown error");
+			break;
+	}
+	fastboot_okay("");
+}
+#endif
+
+#ifdef MTK_TC7_COMMON_DEVICE_INTERFACE
+void cmd_oem_ADB_Auto_Enable(const char *arg, void *data, unsigned sz)
+{
+	char *str_enable = " enable";
+	char *str_disable = " disable";
+	char *str_help = " help";
+	if (adb_cmdline_appended) {
+		if (memcmp(arg, str_enable, strlen(str_enable)) == 0) {
+			*head_of_adb_cmdline = '1';
+			dprintf(INFO, "[FASTBOOT] New command line:%s\n", cmdline_get());
+			fastboot_okay("");
+			return;
+		} else if (memcmp(arg, str_disable, strlen(str_disable)) == 0) {
+			*head_of_adb_cmdline = '0';
+			dprintf(INFO, "[FASTBOOT] New command line:%s\n", cmdline_get());
+			fastboot_okay("");
+			return;
+		} else if (memcmp(arg, str_help, strlen(str_help)) == 0) {
+			fastboot_info("fastboot oem auto-ADB enable    Enable Auto ADB");
+			fastboot_info("fastboot oem auto-ADB disable   Disable Auto ADB");
+			fastboot_okay("");
+			return;
+		} else
+			fastboot_fail("Please enter correct cmd");
+	} else {
+		if (memcmp(arg, str_enable, strlen(str_enable)) == 0) {
+			cmd_oem_append_cmdline(" AdbAutoEnable=1", data, sz);
+			head_of_adb_cmdline = strchr(cmdline_get(), '\0') - 0x1;
+			dprintf(INFO, "Head of auto-adb cmd %p,%s\n", head_of_adb_cmdline,
+				head_of_adb_cmdline);
+			adb_cmdline_appended = 1;
+			return;
+		} else if (memcmp(arg, str_disable, strlen(str_disable)) == 0) {
+			cmd_oem_append_cmdline(" AdbAutoEnable=0", data, sz);
+			head_of_adb_cmdline = strchr(cmdline_get(), '\0') - 0x1;
+			dprintf(INFO, "Head of auto-adb cmd %p,%s\n", head_of_adb_cmdline,
+				head_of_adb_cmdline);
+			adb_cmdline_appended = 1;
+			return;
+		} else if (memcmp(arg, str_help, strlen(str_help)) == 0) {
+			fastboot_info("fastboot oem auto-ADB enable:  enable Auto ADB");
+			fastboot_info("fastboot oem auto-ADB disable: disable Auto ADB");
+			fastboot_okay("");
+			return;
+		} else
+			fastboot_fail("Please enter correct cmd");
+	}
+	return;
+}
+#endif
+
+void set_p2u(int mode)
+{
+	if (mode == 1) {
+		if (cmdline_append("printk.disable_uart=0") == false) {
+			dprintf(CRITICAL, "command line is too long, will not set printk_on\n");
+			fastboot_info("command line is too long, will not set printk_on");
+		} else
+			fastboot_info("printk to uart is on!");
+	} else if (mode == 2) {
+		if (cmdline_append("printk.disable_uart=1") == false) {
+			dprintf(CRITICAL, "command line is too long, will not set printk_off\n");
+			fastboot_info("command line is too long, will not set printk_off");
+		} else
+			fastboot_info("printk to uart is off!");
+	}
+}
+
+void cmd_continue(const char *arg, void *data, unsigned sz)
+{
+	g_boot_mode = NORMAL_BOOT;
+	if (has_set_p2u) {
+		set_p2u(has_set_p2u);
+		fastboot_info("phone will continue boot up after 5s...");
+		fastboot_okay("");
+		mdelay(5000);
+	} else
+		fastboot_okay("");
+	udc_stop();
+	//mtk_wdt_init(); //re-open wdt
+	timer_cancel(&wdt_timer);
+	mtk_wdt_restart();
+
+	/*Will not return*/
+	boot_linux_from_storage();
+}
+
+#ifdef FASTBOOT_DUMP_LOG
+#define LK_LOG_DUMP_SIZE (21)
+void cmd_oem_dump_log(const char *arg, void *data, unsigned int sz)
+{
+	u32 add, size, i;
+	char buf[LK_LOG_DUMP_SIZE];
+
+	memset(buf, 0, LK_LOG_DUMP_SIZE);
+	add = current_buf_addr_get();
+	size = current_buf_pl_lk_log_size_get();
+	log_store_enable = false;
+	for (i = 0; i < size / (LK_LOG_DUMP_SIZE-1); i++) {
+		memcpy(buf, (void *)(add + i*(LK_LOG_DUMP_SIZE-1)), (LK_LOG_DUMP_SIZE-1));
+		fastboot_info(buf);
+	}
+	fastboot_okay("");
+	log_store_enable = true;
+}
+#endif
+
+void cmd_printk_ratelimit(const char *arg, void *data, unsigned sz)
+{
+	if (!strncmp(arg, " on", strlen(" on"))){
+		dprintf(INFO, "SET PRINTK RATELIMIT ON\n");
+		fastboot_info("SET PRINTK RATELIMIT ON\n");
+		set_printk_ratelimit(false);
+		dprintf(INFO, "SET PRINTK RATELIMIT SUCCESS\n");
+		fastboot_okay("SET PRINTK RATELIMIT SUCCESS\n");
+	} else if (!strncmp(arg, " off", strlen(" off"))) {
+		dprintf(INFO, "SET PRINTK RATELIMIT OFF\n");
+		fastboot_info("SET PRINTK RATELIMIT OFF\n");
+		set_printk_ratelimit(true);
+		dprintf(INFO, "SET PRINTK RATELIMIT OFF SUCCESS\n");
+		fastboot_okay("SET PRINTK RATELIMIT OFF SUCCESS\n");
+	} else {
+		dprintf(INFO, "UNKNOWN ARGUMENT\n");
+		fastboot_info("UNKNOWN ARGUMENT\n");
+	}
+}
+
+void cmd_oem_p2u(const char *arg, void *data, unsigned sz)
+{
+	if (!strncmp(arg, " on", strlen(" on"))){
+		has_set_p2u = 1;
+#ifdef LOG_STORE_SUPPORT
+		g_boot_arg->log_dynamic_switch = 1;
+		set_uart_log_flag(true);
+#endif
+	} else if (!strncmp(arg, " off", strlen(" off"))) {
+		has_set_p2u = 2;
+#ifdef LOG_STORE_SUPPORT
+		g_boot_arg->log_dynamic_switch = 0;
+		set_uart_log_flag(false);
+#endif
+	} else {
+		has_set_p2u = 0;
+		fastboot_info("unknown argument");
+	}
+	fastboot_okay("");
+}
+
+void cmd_reboot_recovery(const char *arg, void *data, unsigned sz)
+{
+	extern void Set_RTC_Recovery_Mode(bool flag)__attribute__((weak));
+
+	if (Set_RTC_Recovery_Mode) {
+		Set_RTC_Recovery_Mode(1);
+		fastboot_okay("");
+		mtk_arch_reset(1); //bypass pwr key when reboot
+	} else
+		fastboot_fail("Not support this function (need RTC porting)");
+}
+
+void cmd_reboot_fastboot(const char *arg, void *data, unsigned sz)
+{
+	if (recovery_set_fastboot_cmd() == FALSE) {
+		fastboot_fail("recovery_set_fastboot_cmd failed");
+        } else {
+		fastboot_okay("");
+		mtk_arch_reset(1); //bypass pwr key when reboot
+        }
+}
+
+#ifdef MTK_OFF_MODE_CHARGE_SUPPORT
+void set_off_mode_charge(int mode)
+{
+	struct fastboot_var *var;
+
+	for (var = varlist; var; var = var->next) {
+		if (!strcmp(var->name, "off-mode-charge"))
+			var->value = (mode == 1) ? "1" : "0";
+	}
+	set_off_mode_charge_status(mode);
+}
+void cmd_oem_off_mode_charge(const char *arg, void *data, unsigned sz)
+{
+	if (!strncmp(arg, " 1", strlen(" 1"))) {
+		//CHARGE MODE
+		set_off_mode_charge(1);
+	} else if (!strncmp(arg, " 0", strlen(" 0"))) {
+		//NORMAL MODE
+		set_off_mode_charge(0);
+	} else
+		fastboot_info("unknown argument");
+	fastboot_okay("");
+}
+#endif
+#ifdef MTK_JTAG_SWITCH_SUPPORT
+extern unsigned int set_ap_jtag(unsigned int);
+extern unsigned int get_ap_jtag(void);
+void cmd_oem_ap_jtag(const char *arg, void *data, unsigned sz)
+{
+	char response[MAX_RSP_SIZE];
+
+	if (!strncmp(arg, " 1", strlen(" 1"))) {
+		//turn ap jtag on
+		fastboot_info("Enable AP JTAG");
+		set_ap_jtag(1);
+	} else if (!strncmp(arg, " 0", strlen(" 0"))) {
+		//turn ap jtag off
+		fastboot_info("Disable AP JTAG");
+		set_ap_jtag(0);
+	} else {
+		int n = snprintf(response, MAX_RSP_SIZE, "\tCurrent AP JTAG setting:%s",
+			 get_ap_jtag() ? "Enable" : "Disable");
+		if (n < 0) {
+			strncpy(response, "unknown error", sizeof(response) - 1);
+			response[sizeof(response) - 1] = '\0';
+		}
+		fastboot_info(response);
+	}
+	fastboot_okay("");
+}
+#endif
+
+
+#ifdef MTK_TINYSYS_SCP_SUPPORT
+/******************************************************************************
+******************************************************************************/
+void cmd_oem_scp_status(const char *arg, void *data, unsigned sz)
+{
+	char response[MAX_RSP_SIZE];
+
+	if (!strncmp(arg, " 1", strlen(" 1"))) {
+		//turn scp on
+		fastboot_info("Turn on SCP");
+		fastboot_info("Plz reboot system to make it applied.");
+		set_scp_status(1);
+	} else if (!strncmp(arg, " 0", strlen(" 0"))) {
+		//turn scp off
+		fastboot_info("Turn off SCP");
+		fastboot_info("Plz reboot system to make it applied.");
+		set_scp_status(0);
+	} else {
+		int n = snprintf(response, MAX_RSP_SIZE, "\tCurrent SCP setting:%s",
+			 get_scp_status() ? "Enable" : "Disable");
+		if (n < 0) {
+			strncpy(response, "unknown error", sizeof(response) - 1);
+			response[sizeof(response) - 1] = '\0';
+		}
+		fastboot_info(response);
+	}
+	fastboot_okay("");
+}
+
+
+/******************************************************************************
+******************************************************************************/
+void cmd_oem_scp_log_thru_ap_uart(const char *arg, void *data, unsigned sz)
+{
+	char response[MAX_RSP_SIZE];
+
+	if (!strncmp(arg, " 1", strlen(" 1"))) {
+		set_scp_log_thru_ap_uart(1);
+		fastboot_info("SCP log thru AP UART: on");
+		fastboot_info("Please reboot to apply the change.");
+	} else if (!strncmp(arg, " 0", strlen(" 0"))) {
+		set_scp_log_thru_ap_uart(0);
+		fastboot_info("SCP log thru AP UART: off");
+		fastboot_info("Please reboot to apply the change.");
+	} else {
+		int n = snprintf(response, MAX_RSP_SIZE, "Get SCP log thru AP UART: %s",
+			get_scp_log_thru_ap_uart() ? "on" : "off");
+		if (n < 0) {
+			strncpy(response, "unknown error", sizeof(response) - 1);
+			response[sizeof(response) - 1] ='\0';
+		}
+		fastboot_info(response);
+	}
+	fastboot_okay("");
+}
+#endif  // MTK_TINYSYS_SCP_SUPPORT
+
+
+#ifdef MTK_USB2JTAG_SUPPORT
+extern unsigned int set_usb2jtag(unsigned int);
+extern unsigned int get_usb2jtag(void);
+void cmd_oem_usb2jtag(const char *arg, void *data, unsigned sz)
+{
+	char response[MAX_RSP_SIZE];
+
+	if (!strncmp(arg, " 1", strlen(" 1"))) {
+		//turn usb2jtag on
+		fastboot_info("Enable USB2JTAG");
+		set_usb2jtag(1);
+	} else if (!strncmp(arg, " 0", strlen(" 0"))) {
+		//turn usb2jtag off
+		fastboot_info("Disable USB2JTAG");
+		set_usb2jtag(0);
+	} else {
+		int n = snprintf(response, MAX_RSP_SIZE, "\tCurrent USB2JTAG setting:%s",
+			 get_usb2jtag() ? "Enable" : "Disable");
+		if (n < 0) {
+			strncpy(response, "unknown error", sizeof(response) - 1);
+			response[sizeof(response) - 1] = '\0';
+		}
+		fastboot_info(response);
+	}
+	fastboot_info("rebooting device for usb2jtag support..\n");
+	fastboot_okay("");
+	mtk_arch_reset(1);
+}
+#endif
+void cmd_getvar(const char *arg, void *data, unsigned sz)
+{
+	struct fastboot_var *var;
+	char response[MAX_RSP_SIZE];
+
+	if (!strcmp(arg, "all")) {
+		for (var = varlist; var; var = var->next) {
+			int n = snprintf(response, MAX_RSP_SIZE, "%s: %s", var->name, var->value);
+			if (n < 0) {
+				strncpy(response, "unknown error", sizeof(response) - 1);
+				response[sizeof(response) - 1] = '\0';
+			}
+			fastboot_info(response);
+		}
+		fastboot_okay("Done!!");
+		return;
+	}
+	for (var = varlist; var; var = var->next) {
+		if (!strcmp(var->name, arg)) {
+			fastboot_okay(var->value);
+			return;
+		}
+	}
+	fastboot_fail("GetVar Variable Not found");
+}
+
+void cmd_reboot(const char *arg, void *data, unsigned sz)
+{
+	dprintf(INFO, "rebooting the device\n");
+	fastboot_okay("");
+#ifdef MTK_MRDUMP_SUPPORT
+	if (after_usb_dump) {
+		dprintf(INFO, "[FASTBOOT] mrdump reset!\n");
+		mrdump_reboot();
+	}
+#endif
+	// Dis-connect USB before hardware reset for avoiding PC HOST was not synced.
+	udc_stop();
+	msleep(800);
+
+#ifdef MTK_PMIC_FULL_RESET
+	mtk_arch_full_reset();
+#else
+	mtk_arch_reset(1); //bypass pwr key when reboot
+#endif
+}
+
+void cmd_reboot_bootloader(const char *arg, void *data, unsigned sz)
+{
+	dprintf(INFO, "rebooting the device to bootloader\n");
+	fastboot_okay("");
+
+	// Dis-connect USB before hardware reset for avoiding PC HOST was not synced.
+	udc_stop();
+	msleep(800);
+
+	Set_Clr_RTC_PDN1_bit13(true); //Set RTC fastboot bit
+	mtk_arch_reset(1); //bypass pwr key when reboot
+}
+
+extern unsigned int g_kmem_off;
+extern unsigned int g_rmem_off;
+extern unsigned int g_bimg_sz;
+#define ROUND_TO_PAGE(x,y) (((x) + (y)) & (~(y)))
+void cmd_boot(const char *arg, void *data, unsigned sz)
+{
+	unsigned kernel_actual;
+	unsigned ramdisk_actual;
+	struct bootimg_hdr *boot_hdr;
+	char *ptr = ((char *) data);
+	unsigned page_sz = 0;
+	unsigned page_mask = 0;
+#define CMDLINE_TMP_CONCAT_SIZE 100     //only for string concat, 100 bytes is enough
+	char cmdline_tmpbuf[CMDLINE_TMP_CONCAT_SIZE];
+
+	boot_hdr = (struct bootimg_hdr *)malloc(sizeof(struct bootimg_hdr));
+
+	if (!boot_hdr) {
+		dprintf(CRITICAL, "cmd_boot,boot_hdr = NULL\n");
+		return;
+	}
+
+	memcpy(boot_hdr, data, sizeof(struct bootimg_hdr));
+	load_bootinfo_bootimg(data);
+
+	dprintf(INFO,
+		"\n============================================================\n");
+	boot_hdr->magic[7] = '\0';
+	dprintf(INFO, "[%s] Android Boot IMG Hdr - Magic 	        : %s\n", MODULE_NAME,
+		boot_hdr->magic);
+	dprintf(INFO, "[%s] Android Boot IMG Hdr - Kernel Size 	: 0x%x\n", MODULE_NAME,
+		boot_hdr->kernel_sz);
+	dprintf(INFO, "[%s] Android Boot IMG Hdr - Kernel addr 	: 0x%x\n", MODULE_NAME,
+		boot_hdr->kernel_addr);
+	dprintf(INFO, "[%s] Android Boot IMG Hdr - Rootfs Size 	: 0x%x\n", MODULE_NAME,
+		boot_hdr->ramdisk_sz);
+	dprintf(INFO, "[%s] Android Boot IMG Hdr - Page Size    	: 0x%x\n", MODULE_NAME,
+		boot_hdr->page_sz);
+	dprintf(INFO, "============================================================\n");
+
+	/* ensure commandline is terminated */
+	boot_hdr->cmdline[BOOTIMG_ARGS_SZ - 1] = 0;
+
+	if (boot_hdr->page_sz) {
+		page_sz = boot_hdr->page_sz;
+		page_mask = page_sz - 1;
+		//page_mask = 2*1024 ; /*FIXME*/
+	} else {
+		dprintf(CRITICAL,
+			"[FASTBOOT] Please specify the storage page-size in the boot header!\n");
+		fastboot_fail("Please specify the storage page-size in the boot header!\n");
+		goto _cmd_boot_exit;
+	}
+
+	kernel_actual = ROUND_TO_PAGE(boot_hdr->kernel_sz, page_mask);
+	ramdisk_actual = ROUND_TO_PAGE(boot_hdr->ramdisk_sz, page_mask);
+
+	/* sz should have atleast raw boot image */
+	if (page_sz + kernel_actual + ramdisk_actual > sz) {
+		fastboot_fail("incomplete bootimage");
+		goto _cmd_boot_exit;
+	}
+
+	if ((boot_hdr->kernel_addr <= ROUND_TO_PAGE((boot_hdr->ramdisk_addr +
+			boot_hdr->ramdisk_sz), page_mask)) &&
+	    (ROUND_TO_PAGE((boot_hdr->kernel_addr + boot_hdr->kernel_sz),
+			   page_mask) >= boot_hdr->ramdisk_addr)) {
+		fastboot_fail("invalid kernel & ramdisk address: images overlap");
+		goto _cmd_boot_exit;
+	}
+
+	if ((boot_hdr->kernel_addr < DRAM_PHY_ADDR) ||
+	    (ROUND_TO_PAGE((boot_hdr->kernel_addr + boot_hdr->kernel_sz),
+			   page_mask) > (DRAM_PHY_ADDR + (u64)memory_size()))) {
+		fastboot_fail("invalid kernel address: not lie in memory");
+		goto _cmd_boot_exit;
+	}
+
+	if ((boot_hdr->kernel_addr <= _heap_end) &&
+	    (ROUND_TO_PAGE((boot_hdr->kernel_addr + boot_hdr->kernel_sz),
+			   page_mask) >= MEMBASE)) {
+		fastboot_fail("invalid kernel address: overlap with lk");
+		goto _cmd_boot_exit;
+	}
+
+	if ((boot_hdr->kernel_addr <= ROUND_TO_PAGE((SCRATCH_ADDR + boot_hdr->kernel_sz
+			+ boot_hdr->ramdisk_sz), page_mask)) &&
+	    (ROUND_TO_PAGE((boot_hdr->kernel_addr + boot_hdr->kernel_sz),
+			   page_mask) >= SCRATCH_ADDR)) {
+		fastboot_fail("invalid kernel address: overlap with the download image");
+		goto _cmd_boot_exit;
+	}
+
+	if ((boot_hdr->ramdisk_addr < DRAM_PHY_ADDR) ||
+	    (ROUND_TO_PAGE((boot_hdr->ramdisk_addr + boot_hdr->ramdisk_sz),
+			   page_mask) > (DRAM_PHY_ADDR + (u64)memory_size()))) {
+		fastboot_fail("invalid ramdisk address: not lie in memory");
+		goto _cmd_boot_exit;
+	}
+
+	if ((boot_hdr->ramdisk_addr <= _heap_end) &&
+	    (ROUND_TO_PAGE((boot_hdr->ramdisk_addr + boot_hdr->ramdisk_sz),
+			   page_mask) >= MEMBASE)) {
+		fastboot_fail("invalid ramdisk address: overlap with lk");
+		goto _cmd_boot_exit;
+	}
+
+	if ((boot_hdr->ramdisk_addr <= ROUND_TO_PAGE((SCRATCH_ADDR + boot_hdr->kernel_sz
+			+ boot_hdr->ramdisk_sz), page_mask)) &&
+	    (ROUND_TO_PAGE((boot_hdr->ramdisk_addr + boot_hdr->ramdisk_sz),
+			   page_mask) >= SCRATCH_ADDR)) {
+		fastboot_fail("invalid ramdisk address: overlap with the download image");
+		goto _cmd_boot_exit;
+	}
+	set_bootimg_loaded((uint32_t)ptr);
+	/* do nothing, since boot image has been loaded in scratch address */
+	//memmove((void *)SCRATCH_ADDR, ptr, boot_hdr->kernel_sz);
+
+#ifdef MTK_3LEVEL_PAGETABLE
+	/* rootfs addr */
+	arch_mmu_map((uint64_t)boot_hdr->ramdisk_addr, (uint32_t)boot_hdr->ramdisk_addr,
+		     MMU_MEMORY_TYPE_NORMAL_WRITE_BACK | MMU_MEMORY_AP_P_RW_U_NA,
+		     ROUNDUP(boot_hdr->ramdisk_sz, PAGE_SIZE));
+#endif
+	memmove((void *) boot_hdr->ramdisk_addr,
+		(ptr + boot_hdr->page_sz + kernel_actual), boot_hdr->ramdisk_sz);
+
+#ifndef MACH_FPGA
+	int n;
+
+	cmdline_append((char *)boot_hdr->cmdline);
+	n = snprintf(cmdline_tmpbuf, CMDLINE_TMP_CONCAT_SIZE, "lcm=%1d-%s",
+		 DISP_IsLcmFound(), mt_disp_get_lcm_id());
+	if (n < 0)
+		dprintf(INFO, "cmdline snprintf error\n");
+	else
+		cmdline_append(cmdline_tmpbuf);
+
+	n = snprintf(cmdline_tmpbuf, CMDLINE_TMP_CONCAT_SIZE, "fps=%1d",
+		 mt_disp_get_lcd_time());
+	if (n < 0)
+		dprintf(INFO, "cmdline snprintf error\n");
+	else
+		cmdline_append(cmdline_tmpbuf);
+
+	n = snprintf(cmdline_tmpbuf, CMDLINE_TMP_CONCAT_SIZE, "vram=%1d",
+		 DISP_GetVRamSize());
+	if (n < 0)
+		dprintf(INFO, "cmdline snprintf error\n");
+	else
+		cmdline_append(cmdline_tmpbuf);
+#endif
+
+#ifdef SELINUX_STATUS
+#if SELINUX_STATUS == 1
+	cmdline_append("androidboot.selinux=disabled");
+#elif SELINUX_STATUS == 2
+	cmdline_append("androidboot.selinux=permissive");
+#endif
+#endif
+
+	fastboot_okay("");
+	udc_stop();
+	//mtk_wdt_init(); //re-open wdt
+	timer_cancel(&wdt_timer);
+	mtk_wdt_restart();
+
+	g_boot_mode = NORMAL_BOOT;
+	custom_port_in_kernel(g_boot_mode, cmdline_get());
+	dprintf(CRITICAL, "Kernel Address: 0x%8X\n", boot_hdr->kernel_addr);
+	dprintf(CRITICAL, "Ramdisk Address: 0x%8X\n", boot_hdr->ramdisk_addr);
+	dprintf(CRITICAL, "Atag Address: 0x%8X\n", boot_hdr->tags_addr);
+	dprintf(CRITICAL, "Command: %s\n", boot_hdr->cmdline);
+
+	boot_linux((void *) boot_hdr->kernel_addr, (void *) boot_hdr->tags_addr,
+		   (char *) cmdline_get(), board_machtype(),
+		   (void *) boot_hdr->ramdisk_addr, boot_hdr->ramdisk_sz);
+_cmd_boot_exit:
+	free(boot_hdr);
+	return;
+
+}
+
+
+#ifdef MTK_AB_OTA_UPDATER
+void cmd_set_active(const char *arg, void *data, unsigned sz)
+{
+	if (!strcmp(arg, "a")) {
+		if (!set_active_slot(BOOTCTRL_SUFFIX_A))
+			fastboot_okay("");
+		else
+			fastboot_fail("set slot a failed!\n");
+	} else if (!strcmp(arg, "b")) {
+		if (!set_active_slot(BOOTCTRL_SUFFIX_B))
+			fastboot_okay("");
+		else
+			fastboot_fail("set slot b failed!\n");
+	} else
+		fastboot_fail("command parameter is not allowed!\n");
+}
+#endif

+ 79 - 0
app/mt_boot/sys_commands.h

@@ -0,0 +1,79 @@
+/* Copyright Statement:
+*
+* This software/firmware and related documentation ("MediaTek Software") are
+* protected under relevant copyright laws. The information contained herein
+* is confidential and proprietary to MediaTek Inc. and/or its licensors.
+* Without the prior written permission of MediaTek inc. and/or its licensors,
+* any reproduction, modification, use or disclosure of MediaTek Software,
+* and information contained herein, in whole or in part, shall be strictly prohibited.
+*/
+/* MediaTek Inc. (C) 2015. All rights reserved.
+*
+* BY OPENING THIS FILE, RECEIVER HEREBY UNEQUIVOCALLY ACKNOWLEDGES AND AGREES
+* THAT THE SOFTWARE/FIRMWARE AND ITS DOCUMENTATIONS ("MEDIATEK SOFTWARE")
+* RECEIVED FROM MEDIATEK AND/OR ITS REPRESENTATIVES ARE PROVIDED TO RECEIVER ON
+* AN "AS-IS" BASIS ONLY. MEDIATEK EXPRESSLY DISCLAIMS ANY AND ALL WARRANTIES,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED WARRANTIES OF
+* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE OR NONINFRINGEMENT.
+* NEITHER DOES MEDIATEK PROVIDE ANY WARRANTY WHATSOEVER WITH RESPECT TO THE
+* SOFTWARE OF ANY THIRD PARTY WHICH MAY BE USED BY, INCORPORATED IN, OR
+* SUPPLIED WITH THE MEDIATEK SOFTWARE, AND RECEIVER AGREES TO LOOK ONLY TO SUCH
+* THIRD PARTY FOR ANY WARRANTY CLAIM RELATING THERETO. RECEIVER EXPRESSLY ACKNOWLEDGES
+* THAT IT IS RECEIVER'S SOLE RESPONSIBILITY TO OBTAIN FROM ANY THIRD PARTY ALL PROPER LICENSES
+* CONTAINED IN MEDIATEK SOFTWARE. MEDIATEK SHALL ALSO NOT BE RESPONSIBLE FOR ANY MEDIATEK
+* SOFTWARE RELEASES MADE TO RECEIVER'S SPECIFICATION OR TO CONFORM TO A PARTICULAR
+* STANDARD OR OPEN FORUM. RECEIVER'S SOLE AND EXCLUSIVE REMEDY AND MEDIATEK'S ENTIRE AND
+* CUMULATIVE LIABILITY WITH RESPECT TO THE MEDIATEK SOFTWARE RELEASED HEREUNDER WILL BE,
+* AT MEDIATEK'S OPTION, TO REVISE OR REPLACE THE MEDIATEK SOFTWARE AT ISSUE,
+* OR REFUND ANY SOFTWARE LICENSE FEES OR SERVICE CHARGE PAID BY RECEIVER TO
+* MEDIATEK FOR SUCH MEDIATEK SOFTWARE AT ISSUE.
+*/
+
+#ifndef __COMMANDS_H
+#define __COMMANDS_H
+
+void cmd_printk_ratelimit(const char *arg, void *data, unsigned sz);
+void cmd_getvar(const char *arg, void *data, unsigned sz);
+void cmd_boot(const char *arg, void *data, unsigned sz);
+void cmd_reboot(const char *arg, void *data, unsigned sz);
+void cmd_reboot_bootloader(const char *arg, void *data, unsigned sz);
+void cmd_reboot_recovery(const char *arg, void *data, unsigned sz);
+void cmd_reboot_fastboot(const char *arg, void *data, unsigned sz);
+void cmd_download(const char *arg, void *data, unsigned sz);
+void cmd_overwirte_cmdline(const char *arg, void *data, unsigned sz);
+void cmd_continue(const char *arg, void *data, unsigned sz);
+void cmd_oem_p2u(const char *arg, void *data, unsigned sz);
+void cmd_oem_append_cmdline(const char *arg, void *data, unsigned sz);
+#ifdef MTK_JTAG_SWITCH_SUPPORT
+void cmd_oem_ap_jtag(const char *arg, void *data, unsigned sz);
+#endif
+
+
+#ifdef MTK_TINYSYS_SCP_SUPPORT
+void cmd_oem_scp_status(const char *arg, void *data, unsigned sz);
+void cmd_oem_scp_log_thru_ap_uart(const char *arg, void *data, unsigned sz);
+#endif  // MTK_TINYSYS_SCP_SUPPORT
+
+
+#ifdef MTK_OFF_MODE_CHARGE_SUPPORT
+void cmd_oem_off_mode_charge(const char *arg, void *data, unsigned sz);
+#endif
+#ifdef MTK_MRDUMP_SUPPORT
+void cmd_oem_mrdump(const char *arg, void *data, unsigned sz);
+void cmd_oem_mrdump_outdev(const char *arg, void *data, unsigned int sz);
+void cmd_oem_mrdump_fallocate(const char *arg, void *data, unsigned int sz);
+void cmd_oem_mrdump_chkimg(const char *arg, void *data, unsigned int sz);
+#endif
+#ifdef MTK_TC7_COMMON_DEVICE_INTERFACE
+void cmd_oem_ADB_Auto_Enable(const char *arg, void *data, unsigned sz);
+#endif
+#ifdef MTK_USB2JTAG_SUPPORT
+void cmd_oem_usb2jtag(const char *arg, void *data, unsigned sz);
+#endif
+#ifdef MTK_AB_OTA_UPDATER
+void cmd_set_active(const char *arg, void *data, unsigned sz);
+#endif
+#ifdef FASTBOOT_DUMP_LOG
+void cmd_oem_dump_log(const char *arg, void *data, unsigned sz);
+#endif
+#endif

+ 220 - 0
app/nandwrite/nandwrite.c

@@ -0,0 +1,220 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ * All rights reserved.
+ * Copyright (c) 2009, Code Aurora Forum. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the
+ *    distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <app.h>
+#include <debug.h>
+#include <lib/ptable.h>
+#include <malloc.h>
+#include <dev/flash.h>
+#include <string.h>
+#include <jtag.h>
+#include <kernel/thread.h>
+#include <smem.h>
+#include <platform.h>
+#include "bootimg.h"
+
+#define FLASH_PAGE_SIZE 2048
+#define FLASH_PAGE_BITS 11
+
+unsigned page_size = 0;
+unsigned page_mask = 0;
+
+static unsigned load_addr = 0xffffffff;
+
+#define ROUND_TO_PAGE(x,y) (((x) + (y)) & (~(y)))
+
+void acpu_clock_init(void);
+
+int startswith(const char *str, const char *prefix)
+{
+    while(*prefix){
+        if (*prefix++ != *str++) return 0;
+    }
+    return 1;
+}
+
+/* XXX */
+void verify_flash(struct ptentry *p, void *addr, unsigned len, int extra)
+{
+    uint32_t offset = 0;
+    void *buf = malloc(FLASH_PAGE_SIZE + extra);
+    int verify_extra = extra;
+    if(verify_extra > 4)
+        verify_extra = 16;
+    while(len > 0) {
+        flash_read_ext(p, extra, offset, buf, FLASH_PAGE_SIZE);
+        if(memcmp(addr, buf, FLASH_PAGE_SIZE + verify_extra)) {
+            dprintf(CRITICAL, "verify failed at 0x%08x\n", offset);
+            jtag_fail("verify failed");
+            return;
+        }
+        offset += FLASH_PAGE_SIZE;
+        addr += FLASH_PAGE_SIZE;
+        len -= FLASH_PAGE_SIZE;
+        if(extra) {
+            addr += extra;
+            len -= extra;
+        }
+    }
+    dprintf(INFO, "verify done %d extra bytes\n", verify_extra);
+    jtag_okay("verify done");
+}
+
+void handle_flash(const char *name, unsigned addr, unsigned sz)
+{
+	struct ptentry *ptn;
+	struct ptable *ptable;
+        void *data = (void *) addr;
+	unsigned extra = 0;
+
+	ptable = flash_get_ptable();
+	if (ptable == NULL) {
+		jtag_fail("partition table doesn't exist");
+		return;
+	}
+
+	ptn = ptable_find(ptable, name);
+	if (ptn == NULL) {
+		jtag_fail("unknown partition name");
+		return;
+	}
+
+	if (!strcmp(ptn->name, "boot") || !strcmp(ptn->name, "recovery")) {
+		if (memcmp((void *)data, BOOT_MAGIC, BOOT_MAGIC_SIZE)) {
+			jtag_fail("image is not a boot image");
+			return;
+		}
+	}
+
+	if (!strcmp(ptn->name, "system") || !strcmp(ptn->name, "userdata") || !strcmp(ptn->name, "persist"))
+		extra = ((page_size >> 9) * 16);
+	else
+		sz = ROUND_TO_PAGE(sz, page_mask);
+
+	data = (void *)target_get_scratch_address();
+
+	dprintf(INFO, "writing %d bytes to '%s'\n", sz, ptn->name);
+	if (flash_write(ptn, extra, data, sz)) {
+		jtag_fail("flash write failure");
+		return;
+	}
+	dprintf(INFO, "partition '%s' updated\n", ptn->name);
+        jtag_okay("Done");
+        enter_critical_section();
+        platform_uninit_timer();
+        arch_disable_cache(UCACHE);
+        arch_disable_mmu();
+}
+
+static unsigned char *tmpbuf = 0;
+
+
+/*XXX*/
+void handle_dump(const char *name, unsigned offset)
+{
+    struct ptentry *p;
+    struct ptable *ptable;
+
+    if(tmpbuf == 0) {
+        tmpbuf = malloc(4096);
+    }
+
+    dprintf(INFO, "dump '%s' partition\n", name);
+
+    ptable = flash_get_ptable();
+
+    if (ptable == NULL) {
+        jtag_fail("partition table doesn't exist");
+        return;
+    }
+
+    p = ptable_find(ptable, name);
+
+    if(p == 0) {
+        jtag_fail("partition not found");
+        return;
+    } else {
+
+#if 0
+        /* XXX reimpl */
+        if(flash_read_page(p->start * 64, tmpbuf, tmpbuf + 2048)){
+            jtag_fail("flash_read() failed");
+            return;
+        }
+#endif
+        dprintf(INFO, "page %d data:\n", p->start * 64);
+        hexdump(tmpbuf, 256);
+        dprintf(INFO, "page %d extra:\n", p->start * 64);
+        hexdump(tmpbuf, 16);
+        jtag_okay("done");
+        enter_critical_section();
+        platform_uninit_timer();
+        arch_disable_cache(UCACHE);
+        arch_disable_mmu();
+    }
+}
+
+void handle_query_load_address(unsigned addr)
+{
+    unsigned *return_addr = (unsigned *)addr;
+
+    if (return_addr)
+        *return_addr = target_get_scratch_address();
+
+    jtag_okay("done");
+}
+
+void handle_command(const char *cmd, unsigned a0, unsigned a1, unsigned a2)
+{
+    if(startswith(cmd,"flash:")){
+        handle_flash(cmd + 6, a0, a1);
+        return;
+    }
+
+    if(startswith(cmd,"dump:")){
+        handle_dump(cmd + 5, a0);
+        return;
+    }
+
+    if(startswith(cmd,"loadaddr:")){
+        handle_query_load_address(a0);
+        return;
+    }
+
+    jtag_fail("unknown command");
+}
+
+void nandwrite_init(void)
+{
+    page_size = flash_page_size();
+    page_mask = page_size - 1;
+    jtag_cmd_loop(handle_command);
+}
+
+

+ 6 - 0
app/nandwrite/rules.mk

@@ -0,0 +1,6 @@
+LOCAL_DIR := $(GET_LOCAL_DIR)
+
+OBJS += \
+	$(LOCAL_DIR)/nandwrite.o \
+
+

+ 249 - 0
app/pcitests/pci_tests.c

@@ -0,0 +1,249 @@
+/*
+ * Copyright (c) 2009 Corey Tabaka
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files
+ * (the "Software"), to deal in the Software without restriction,
+ * including without limitation the rights to use, copy, modify, merge,
+ * publish, distribute, sublicense, and/or sell copies of the Software,
+ * and to permit persons to whom the Software is furnished to do so,
+ * subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+ * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+#include <app.h>
+#include <debug.h>
+#include <stdint.h>
+#include <string.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <compiler.h>
+#include <platform.h>
+#include <dev/pci.h>
+
+#if defined(WITH_LIB_CONSOLE)
+#include <lib/console.h>
+
+/*
+ * enumerates pci devices
+ */
+static void pci_list(void)
+{
+	pci_location_t state;
+	uint16_t device_id, vendor_id;
+	uint8_t header_type;
+	int busses = 0, devices = 0, lines = 0, devfn, ret;
+	char c;
+	
+	printf("Scanning...\n");
+	
+	for (state.bus = 0; state.bus <= pci_get_last_bus(); state.bus++) {
+		busses++;
+		
+		for (devfn = 0; devfn < 256; devfn++) {
+			state.dev_fn = devfn;
+			
+			ret = pci_read_config_half(&state, PCI_CONFIG_VENDOR_ID, &vendor_id);
+			if (ret != _PCI_SUCCESSFUL) goto error;
+			
+			ret = pci_read_config_half(&state, PCI_CONFIG_DEVICE_ID, &device_id);
+			if (ret != _PCI_SUCCESSFUL) goto error;
+			
+			ret = pci_read_config_byte(&state, PCI_CONFIG_HEADER_TYPE, &header_type);
+			if (ret != _PCI_SUCCESSFUL) goto error;
+			
+			if (vendor_id != 0xffff) {
+				printf("%02x:%02x vendor_id=%04x device_id=%04x, header_type=%02x\n", state.bus, state.dev_fn,
+						vendor_id, device_id, header_type);
+				devices++;
+				lines++;
+			}
+			
+			if (~header_type & PCI_HEADER_TYPE_MULTI_FN) {
+				// this is not a multi-function device, so advance to the next device
+				devfn |= 7;
+			}
+			
+			if (lines == 23) {
+				printf("... press any key to continue, q to quit ...");
+				while(getc(&c) < 0);
+				printf("\n");
+				lines = 0;
+				
+				if (c == 'q' || c == 'Q') goto quit;
+			}
+		}
+	}
+
+	printf("... done. Scanned %d busses, %d device/functions\n", busses, devices);
+quit:
+	return;
+	
+error:
+	printf("Error while reading PCI config space: %02x\n", ret);
+}
+
+/*
+ * a somewhat fugly pci config space examine/modify command. this should probably
+ * be broken up a bit.
+ */
+static int pci_config(int argc, const cmd_args *argv)
+{
+	pci_location_t loc;
+	pci_config_t config;
+	uint32_t offset;
+	unsigned int i;
+	int ret;
+	
+	if (argc < 5) {
+		return -1;
+	}
+	
+	if (!strcmp(argv[2].str, "dump")) {
+		loc.bus = atoui(argv[3].str);
+		loc.dev_fn = atoui(argv[4].str);
+		
+		for (i=0; i < sizeof(pci_config_t); i++) {
+			ret = pci_read_config_byte(&loc, i, (uint8_t *) &config + i);
+			if (ret != _PCI_SUCCESSFUL) goto error;
+		}
+		
+		printf("Device at %02x:%02x vendor id=%04x device id=%04x\n", loc.bus,
+			loc.dev_fn, config.vendor_id, config.device_id);
+		printf("command=%04x status=%04x pi=%02x sub cls=%02x base cls=%02x\n",
+			config.command, config.status, config.program_interface,
+			config.sub_class, config.base_class);
+		
+		for (i=0; i < 6; i+=2) {
+			printf("bar%d=%08x  bar%d=%08x\n", i, config.base_addresses[i],
+				i+1, config.base_addresses[i+1]);
+		}
+	} else if (!strcmp(argv[2].str, "rb") || !strcmp(argv[2].str, "rh") || !strcmp(argv[2].str, "rw")) {
+		if (argc != 6) {
+			return -1;
+		}
+		
+		loc.bus = atoui(argv[3].str);
+		loc.dev_fn = atoui(argv[4].str);
+		offset = atoui(argv[5].str);
+		
+		switch (argv[2].str[1]) {
+			case 'b': {
+				uint8_t value;
+				ret = pci_read_config_byte(&loc, offset, &value);
+				if (ret != _PCI_SUCCESSFUL) goto error;
+				
+				printf("byte at device %02x:%02x config offset %04x: %02x\n", loc.bus, loc.dev_fn, offset, value);
+			}
+			break;
+			
+			case 'h': {
+				uint16_t value;
+				ret = pci_read_config_half(&loc, offset, &value);
+				if (ret != _PCI_SUCCESSFUL) goto error;
+				
+				printf("half at device %02x:%02x config offset %04x: %04x\n", loc.bus, loc.dev_fn, offset, value);
+			}
+			break;
+			
+			case 'w': {
+				uint32_t value;
+				ret = pci_read_config_word(&loc, offset, &value);
+				if (ret != _PCI_SUCCESSFUL) goto error;
+				
+				printf("word at device %02x:%02x config offset %04x: %08x\n", loc.bus, loc.dev_fn, offset, value);
+			}
+			break;
+		}
+	} else if (!strcmp(argv[2].str, "mb") || !strcmp(argv[2].str, "mh") || !strcmp(argv[2].str, "mw")) {
+		if (argc != 7) {
+			return -1;
+		}
+		
+		loc.bus = atoui(argv[3].str);
+		loc.dev_fn = atoui(argv[4].str);
+		offset = atoui(argv[5].str);
+		
+		switch (argv[2].str[1]) {
+			case 'b': {
+				uint8_t value = atoui(argv[6].str);
+				ret = pci_write_config_byte(&loc, offset, value);
+				if (ret != _PCI_SUCCESSFUL) goto error;
+				
+				printf("byte to device %02x:%02x config offset %04x: %02x\n", loc.bus, loc.dev_fn, offset, value);
+			}
+			break;
+			
+			case 'h': {
+				uint16_t value = atoui(argv[6].str);
+				ret = pci_write_config_half(&loc, offset, value);
+				if (ret != _PCI_SUCCESSFUL) goto error;
+				
+				printf("half to device %02x:%02x config offset %04x: %04x\n", loc.bus, loc.dev_fn, offset, value);
+			}
+			break;
+			
+			case 'w': {
+				uint32_t value = atoui(argv[6].str);
+				ret = pci_write_config_word(&loc, offset, value);
+				if (ret != _PCI_SUCCESSFUL) goto error;
+				
+				printf("word to device %02x:%02x config offset %04x: %08x\n", loc.bus, loc.dev_fn, offset, value);
+			}
+			break;
+		}
+	} else {
+		return -1;
+	}
+	
+	return 0;
+
+error:
+	printf("Error while reading PCI config space: %02x\n", ret);
+	return -2;
+}
+
+static int pci_cmd(int argc, const cmd_args *argv)
+{
+	if (argc < 2) {
+		printf("pci commands:\n");
+usage:
+		printf("%s list\n", argv[0].str);
+		printf("%s config dump <bus> <devfn>\n", argv[0].str);
+		printf("%s config <rb|rh|rw> <bus> <devfn> <offset>\n", argv[0].str);
+		printf("%s config <mb|mh|mw> <bus> <devfn> <offset> <value>\n", argv[0].str);
+		goto out;
+	}
+	
+	if (!strcmp(argv[1].str, "list")) {
+		pci_list();
+	} else if (!strcmp(argv[1].str, "config")) {
+		if (pci_config(argc, argv)) {
+			goto usage;
+		}
+	} else {
+		goto usage;
+	}
+
+out:
+	return 0;
+}
+
+STATIC_COMMAND_START
+{ "pci", "pci toolbox", &pci_cmd },
+STATIC_COMMAND_END(pcitests);
+
+#endif
+
+APP_START(pcitests)
+APP_END
+

+ 6 - 0
app/pcitests/rules.mk

@@ -0,0 +1,6 @@
+LOCAL_DIR := $(GET_LOCAL_DIR)
+
+#INCLUDES += -I$(LOCAL_DIR)/include
+
+OBJS += \
+	$(LOCAL_DIR)/pci_tests.o 

+ 12 - 0
app/rules.mk

@@ -0,0 +1,12 @@
+LOCAL_DIR := $(GET_LOCAL_DIR)
+
+MODULES += \
+
+ifeq ($(DEVICE_TREE_SUPPORT), yes)
+MODULES += lib/libfdt
+MODULES += lib/libufdt
+endif
+
+OBJS += \
+	$(LOCAL_DIR)/app.o
+

+ 7 - 0
app/shell/rules.mk

@@ -0,0 +1,7 @@
+LOCAL_DIR := $(GET_LOCAL_DIR)
+
+MODULES += \
+	lib/console
+
+OBJS += \
+	$(LOCAL_DIR)/shell.o

+ 41 - 0
app/shell/shell.c

@@ -0,0 +1,41 @@
+/*
+ * Copyright (c) 2009 Travis Geiselbrecht
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files
+ * (the "Software"), to deal in the Software without restriction,
+ * including without limitation the rights to use, copy, modify, merge,
+ * publish, distribute, sublicense, and/or sell copies of the Software,
+ * and to permit persons to whom the Software is furnished to do so,
+ * subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+ * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+#include <app.h>
+#include <debug.h>
+#include <lib/console.h>
+
+static void shell_init(const struct app_descriptor *app)
+{
+	console_init();
+}
+
+static void shell_entry(const struct app_descriptor *app, void *args)
+{
+	console_start();
+}
+
+APP_START(shell)
+	.init = shell_init,
+	.entry = shell_entry,
+APP_END
+

+ 169 - 0
app/stringtests/mymemcpy.S

@@ -0,0 +1,169 @@
+/*
+ * Copyright (c) 2008 Travis Geiselbrecht
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files
+ * (the "Software"), to deal in the Software without restriction,
+ * including without limitation the rights to use, copy, modify, merge,
+ * publish, distribute, sublicense, and/or sell copies of the Software,
+ * and to permit persons to whom the Software is furnished to do so,
+ * subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+ * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+#include <asm.h>
+#include <arch/arm/cores.h>
+
+.text
+.align 2
+
+	.global mymemcpy
+mymemcpy:
+	// check for zero length copy or the same pointer
+	cmp		r2, #0
+	cmpne	r1, r0
+	bxeq	lr
+
+	// save a few registers for use and the return code (input dst)
+	stmfd	sp!, {r0, r4, r5, lr}
+
+	// check for forwards overlap (src > dst, distance < len)
+	subs	r3, r0, r1
+	cmpgt	r2, r3
+	bgt		.L_forwardoverlap
+
+	// check for a short copy len.
+	// 20 bytes is enough so that if a 16 byte alignment needs to happen there is at least a 
+	//   wordwise copy worth of work to be done.
+	cmp		r2, #(16+4)
+	blt		.L_bytewise
+
+	// see if they are similarly aligned on 4 byte boundaries
+	eor		r3, r0, r1
+	tst		r3, #3
+	bne		.L_bytewise		// dissimilarly aligned, nothing we can do (for now)
+
+	// check for 16 byte alignment on dst.
+	// this will also catch src being not 4 byte aligned, since it is similarly 4 byte 
+	//   aligned with dst at this point.
+	tst		r0, #15
+	bne		.L_not16bytealigned
+
+	// check to see if we have at least 32 bytes of data to copy.
+	// if not, just revert to wordwise copy
+	cmp		r2, #32
+	blt		.L_wordwise
+
+.L_bigcopy:
+	// copy 32 bytes at a time. src & dst need to be at least 4 byte aligned, 
+	// and we need at least 32 bytes remaining to copy
+
+	// save r6-r7 for use in the big copy
+	stmfd	sp!, {r6-r7}
+
+	sub		r2, r2, #32		// subtract an extra 32 to the len so we can avoid an extra compare
+
+.L_bigcopy_loop:
+	ldmia	r1!, {r4, r5, r6, r7}
+	stmia	r0!, {r4, r5, r6, r7}
+	ldmia	r1!, {r4, r5, r6, r7}
+	subs	r2, r2, #32
+	stmia	r0!, {r4, r5, r6, r7}
+	bge		.L_bigcopy_loop
+
+	// restore r6-r7
+	ldmfd	sp!, {r6-r7}
+
+	// see if we are done
+	adds	r2, r2, #32
+	beq		.L_done
+
+	// less then 4 bytes left?
+	cmp		r2, #4
+	blt		.L_bytewise
+
+.L_wordwise:
+	// copy 4 bytes at a time.
+	// src & dst are guaranteed to be word aligned, and at least 4 bytes are left to copy.
+	subs	r2, r2, #4
+
+.L_wordwise_loop:
+	ldr		r3, [r1], #4
+	subs	r2, r2, #4
+	str		r3, [r0], #4
+	bge		.L_wordwise_loop
+
+	// correct the remaining len and test for completion
+	adds	r2, r2, #4	
+	beq		.L_done
+
+.L_bytewise:
+	// simple bytewise copy
+	ldrb	r3, [r1], #1
+	subs	r2, r2, #1
+	strb	r3, [r0], #1
+	bgt		.L_bytewise
+
+.L_done:
+	// load dst for return and restore r4,r5
+#if ARM_ARCH_LEVEL >= 5
+	ldmfd	sp!, {r0, r4, r5, pc}
+#else
+	ldmfd	sp!, {r0, r4, r5, lr}
+	bx		lr
+#endif
+
+.L_not16bytealigned:
+	// dst is not 16 byte aligned, so we will copy up to 15 bytes to get it aligned.
+	// src is guaranteed to be similarly word aligned with dst.
+
+	// set the condition flags based on the alignment.
+	lsl		r12, r0, #28
+	rsb		r12, r12, #0
+	msr		CPSR_f, r12				// move into NZCV fields in CPSR
+
+	// move as many bytes as necessary to get the dst aligned
+	ldrvsb	r3, [r1], #1			// V set
+	ldrcsh	r4, [r1], #2			// C set
+	ldreq	r5, [r1], #4			// Z set
+
+	strvsb	r3, [r0], #1
+	strcsh	r4, [r0], #2
+	streq	r5, [r0], #4
+
+	ldmmiia	r1!, {r3-r4}			// N set
+	stmmiia	r0!, {r3-r4}
+
+	// fix the remaining len
+	sub		r2, r2, r12, lsr #28
+
+	// test to see what we should do now
+	cmp		r2, #32
+	bge		.L_bigcopy
+	b		.L_wordwise
+	
+	// src and dest overlap 'forwards' or dst > src
+.L_forwardoverlap:
+
+	// do a bytewise reverse copy for now
+	add		r1, r1, r2
+	add		r0, r0, r2
+
+.L_bytewisereverse:
+	// simple bytewise reverse copy
+	ldrb	r3, [r1], #-1
+	subs	r2, r2, #1
+	strb	r3, [r0], #-1
+	bgt		.L_bytewisereverse
+
+	b		.L_done
+

+ 109 - 0
app/stringtests/mymemset.S

@@ -0,0 +1,109 @@
+/*
+ * Copyright (c) 2008 Travis Geiselbrecht
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files
+ * (the "Software"), to deal in the Software without restriction,
+ * including without limitation the rights to use, copy, modify, merge,
+ * publish, distribute, sublicense, and/or sell copies of the Software,
+ * and to permit persons to whom the Software is furnished to do so,
+ * subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+ * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+#include <asm.h>
+#include <arch/arm/cores.h>
+
+.text
+.align 2
+
+/* void *memset(void *s, int c, size_t n); */
+	.global mymemset
+mymemset:
+	// check for zero length
+	cmp		r2, #0
+	bxeq	lr
+
+	// save the original pointer
+	mov		r12, r0
+
+	// short memsets aren't worth optimizing
+	cmp		r2, #(32 + 16)
+	blt		.L_bytewise
+
+	// fill a 32 bit register with the 8 bit value
+	and		r1, r1, #0xff
+	orr		r1, r1, r1, lsl #8
+	orr		r1, r1, r1, lsl #16
+
+	// check for 16 byte alignment
+	tst		r0, #15
+	bne		.L_not16bytealigned
+
+.L_bigset:
+	// dump some registers to make space for our values
+	stmfd	sp!, { r4-r5 }
+	
+	// fill a bunch of registers with the set value
+	mov		r3, r1
+	mov		r4, r1
+	mov		r5, r1
+
+	// prepare the count register so we can avoid an extra compare
+	sub 	r2, r2, #32
+
+	// 32 bytes at a time
+.L_bigset_loop:
+	stmia	r0!, { r1, r3, r4, r5 }
+	subs	r2, r2, #32
+	stmia	r0!, { r1, r3, r4, r5 }
+	bge		.L_bigset_loop
+
+	// restore our dumped registers
+	ldmfd	sp!, { r4-r5 }
+
+	// see if we're done
+	adds	r2, r2, #32
+	beq		.L_done
+
+.L_bytewise:
+	// bytewise memset
+	subs	r2, r2, #1
+	strb	r1, [r0], #1
+	bgt		.L_bytewise
+
+.L_done:
+	// restore the base pointer as return value
+	mov		r0, r12
+	bx		lr
+
+.L_not16bytealigned:
+	// dst is not 16 byte aligned, so we will set up to 15 bytes to get it aligned.
+
+	// set the condition flags based on the alignment.
+	lsl     r3, r0, #28
+	rsb     r3, r3, #0
+	msr     CPSR_f, r3             // move into NZCV fields in CPSR
+
+	// move as many bytes as necessary to get the dst aligned
+	strvsb  r1, [r0], #1			// V set
+	strcsh  r1, [r0], #2			// C set
+	streq   r1, [r0], #4			// Z set
+	strmi   r1, [r0], #4			// N set
+	strmi   r1, [r0], #4			// N set
+
+	// fix the remaining len
+	sub     r2, r2, r3, lsr #28
+
+	// do the large memset
+	b       .L_bigset
+

+ 6 - 0
app/stringtests/rules.mk

@@ -0,0 +1,6 @@
+LOCAL_DIR := $(GET_LOCAL_DIR)
+
+OBJS += \
+	$(LOCAL_DIR)/string_tests.o \
+	$(LOCAL_DIR)/mymemcpy.o \
+	$(LOCAL_DIR)/mymemset.o

+ 285 - 0
app/stringtests/string_tests.c

@@ -0,0 +1,285 @@
+/*
+ * Copyright (c) 2008 Travis Geiselbrecht
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files
+ * (the "Software"), to deal in the Software without restriction,
+ * including without limitation the rights to use, copy, modify, merge,
+ * publish, distribute, sublicense, and/or sell copies of the Software,
+ * and to permit persons to whom the Software is furnished to do so,
+ * subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+ * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+#include <debug.h>
+#include <string.h>
+#include <malloc.h>
+#include <app.h>
+#include <platform.h>
+#include <kernel/thread.h>
+
+static uint8_t *src;
+static uint8_t *dst;
+
+static uint8_t *src2;
+static uint8_t *dst2;
+
+#define BUFFER_SIZE (1024*1024)
+#define ITERATIONS 16
+
+extern void *mymemcpy(void *dst, const void *src, size_t len);
+extern void *mymemset(void *dst, int c, size_t len);
+
+static void *null_memcpy(void *dst, const void *src, size_t len)
+{
+	return dst;
+}
+
+static time_t bench_memcpy_routine(void *memcpy_routine(void *, const void *, size_t), size_t srcalign, size_t dstalign)
+{
+	int i;
+	time_t t0;
+
+	t0 = current_time();
+	for (i=0; i < ITERATIONS; i++) {
+		memcpy_routine(dst + dstalign, src + srcalign, BUFFER_SIZE);
+	}
+	return current_time() - t0;
+}
+
+static void bench_memcpy(void)
+{
+	time_t null, libc, mine;
+	size_t srcalign, dstalign;
+	
+	printf("memcpy speed test\n");
+	thread_sleep(200); // let the debug string clear the serial port
+
+	for (srcalign = 0; srcalign < 64; ) {
+		for (dstalign = 0; dstalign < 64; ) {
+
+			null = bench_memcpy_routine(&null_memcpy, srcalign, dstalign);
+			libc = bench_memcpy_routine(&memcpy, srcalign, dstalign);
+			mine = bench_memcpy_routine(&mymemcpy, srcalign, dstalign);
+
+			printf("srcalign %lu, dstalign %lu\n", srcalign, dstalign);
+			printf("   null memcpy %u msecs\n", null);
+			printf("   libc memcpy %u msecs, %llu bytes/sec\n", libc, BUFFER_SIZE * ITERATIONS * 1000ULL / libc);
+			printf("   my   memcpy %u msecs, %llu bytes/sec\n", mine, BUFFER_SIZE * ITERATIONS * 1000ULL / mine);
+
+			if (dstalign == 0)
+				dstalign = 1;
+			else 
+				dstalign <<= 1;
+		}
+		if (srcalign == 0)
+			srcalign = 1;
+		else 
+			srcalign <<= 1;
+	}
+}
+
+static void fillbuf(void *ptr, size_t len, uint32_t seed)
+{
+	size_t i;
+
+	for (i = 0; i < len; i++) {
+		((char *)ptr)[i] = seed;
+		seed *= 0x1234567;
+	}
+}
+
+static void validate_memcpy(void)
+{
+	size_t srcalign, dstalign, size;
+	const size_t maxsize = 256;
+
+	printf("testing memcpy for correctness\n");
+
+	/*
+	 * do the simple tests to make sure that memcpy doesn't color outside
+	 * the lines for all alignment cases
+	 */
+	for (srcalign = 0; srcalign < 64; srcalign++) {
+		for (dstalign = 0; dstalign < 64; dstalign++) {
+//			printf("srcalign %zu, dstalign %zu\n", srcalign, dstalign);
+			for (size = 0; size < maxsize; size++) {
+
+//				printf("srcalign %zu, dstalign %zu, size %zu\n", srcalign, dstalign, size);
+
+				fillbuf(src, maxsize * 2, 567);
+				fillbuf(src2, maxsize * 2, 567);
+				fillbuf(dst, maxsize * 2, 123514);
+				fillbuf(dst2, maxsize * 2, 123514);
+
+				memcpy(dst + dstalign, src + srcalign, size);
+				mymemcpy(dst2 + dstalign, src2 + srcalign, size);
+
+				int comp = memcmp(dst, dst2, maxsize * 2);
+				if (comp != 0) {
+					printf("error! srcalign %zu, dstalign %zu, size %zu\n", srcalign, dstalign, size);
+				}
+			}
+		}
+	}
+}
+
+static void validate_memcpy_overlap(void)
+{
+	size_t srcalign, dstalign, size;
+	const size_t maxsize = 256;
+	int comp;
+
+	printf("testing memcpy for correctness in overlap cases\n");
+
+	for (dstalign = 0; dstalign < 64; dstalign++) {
+		for (size = 0; size < maxsize; size++) {
+
+			fillbuf(src, maxsize * 2, 567);
+			fillbuf(src2, maxsize * 2, 567);
+
+			/* Case one will check cpy memory is the same - fwd*/
+			memcpy(src + dstalign, src, size);
+			comp = memcmp(src + dstalign, src2, size);
+			if (comp != 0) {
+				printf("ERROR (Case1): dstalign %zu, size %zu, ret %d\n", dstalign, size, comp);
+			}
+
+			fillbuf(src, maxsize * 2, 8588485);
+			fillbuf(src2, maxsize * 2, 8588485);
+
+			/* Case two will check cpy memory is the same - bkwd*/
+			memcpy(src, src + dstalign, size);
+			comp = memcmp(src, src2 + dstalign, size);
+			if (comp != 0) {
+				printf("ERROR (Case2): dstalign %zu, size %zu, ret %d\n", dstalign, size, comp);
+			}
+		}
+	}
+}
+
+static time_t bench_memset_routine(void *memset_routine(void *, int, size_t), size_t dstalign)
+{
+	int i;
+	time_t t0;
+
+	t0 = current_time();
+	for (i=0; i < ITERATIONS; i++) {
+		memset_routine(dst + dstalign, 0, BUFFER_SIZE);
+	}
+	return current_time() - t0;
+}
+
+static void bench_memset(void)
+{
+	time_t libc, mine;
+	size_t dstalign;
+	
+	printf("memset speed test\n");
+	thread_sleep(200); // let the debug string clear the serial port
+
+	for (dstalign = 0; dstalign < 64; dstalign++) {
+
+		libc = bench_memset_routine(&memset, dstalign);
+		mine = bench_memset_routine(&mymemset, dstalign);
+
+		printf("dstalign %lu\n", dstalign);
+		printf("   libc memset %u msecs, %llu bytes/sec\n", libc, BUFFER_SIZE * ITERATIONS * 1000ULL / libc);
+		printf("   my   memset %u msecs, %llu bytes/sec\n", mine, BUFFER_SIZE * ITERATIONS * 1000ULL / mine);
+	}
+}
+
+static void validate_memset(void)
+{
+	size_t dstalign, size;
+	int c;
+	const size_t maxsize = 256;
+
+	printf("testing memset for correctness\n");
+
+	for (dstalign = 0; dstalign < 64; dstalign++) {
+		printf("align %zd\n", dstalign);
+		for (size = 0; size < maxsize; size++) {
+			for (c = 0; c < 256; c++) {
+
+				fillbuf(dst, maxsize * 2, 123514);
+				fillbuf(dst2, maxsize * 2, 123514);
+
+				memset(dst + dstalign, c, size);
+				mymemset(dst2 + dstalign, c, size);
+
+				int comp = memcmp(dst, dst2, maxsize * 2);
+				if (comp != 0) {
+					printf("error! align %zu, c %d, size %zu\n", dstalign, c, size);
+				}
+			}
+		}
+	}
+}
+
+#if defined(WITH_LIB_CONSOLE)
+#include <lib/console.h>
+
+static int string_tests(int argc, cmd_args *argv)
+{
+	src = memalign(64, BUFFER_SIZE + 256);
+	dst = memalign(64, BUFFER_SIZE + 256);
+	src2 = memalign(64, BUFFER_SIZE + 256);
+	dst2 = memalign(64, BUFFER_SIZE + 256);
+
+	printf("src %p, dst %p\n", src, dst);
+	printf("src2 %p, dst2 %p\n", src2, dst2);
+
+	if (argc < 3) {
+		printf("not enough arguments:\n");
+usage:
+		printf("%s validate <routine>\n", argv[0].str);
+		printf("%s bench <routine>\n", argv[0].str);
+		goto out;
+	}
+
+	if (!strcmp(argv[1].str, "validate")) {
+		if (!strcmp(argv[2].str, "memcpy")) {
+			validate_memcpy();
+		} else if (!strcmp(argv[2].str, "memset")) {
+			validate_memset();
+		} else if (!strcmp(argv[2].str, "memcpy_overlap")) {
+			validate_memcpy_overlap();
+		}
+	} else if (!strcmp(argv[1].str, "bench")) {
+		if (!strcmp(argv[2].str, "memcpy")) {
+			bench_memcpy();
+		} else if (!strcmp(argv[2].str, "memset")) {
+			bench_memset();
+		}
+	} else {
+		goto usage;
+	}
+
+out:
+	free(src);
+	free(dst);
+	free(src2);
+	free(dst2);
+
+	return 0;
+}
+
+STATIC_COMMAND_START
+{ "string", NULL, &string_tests },
+STATIC_COMMAND_END(stringtests);
+
+#endif
+
+APP_START(stringtests)
+APP_END
+

+ 30 - 0
app/tests/include/app/tests.h

@@ -0,0 +1,30 @@
+/*
+ * Copyright (c) 2008 Travis Geiselbrecht
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files
+ * (the "Software"), to deal in the Software without restriction,
+ * including without limitation the rights to use, copy, modify, merge,
+ * publish, distribute, sublicense, and/or sell copies of the Software,
+ * and to permit persons to whom the Software is furnished to do so,
+ * subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+ * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+#ifndef __APP_TESTS_H
+#define __APP_TESTS_H
+
+int thread_tests(void);
+void printf_tests(void);
+
+#endif
+

+ 72 - 0
app/tests/led_tests.c

@@ -0,0 +1,72 @@
+/*
+ * Copyright (c) 2011, Code Aurora Forum. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ *       copyright notice, this list of conditions and the following
+ *       disclaimer in the documentation and/or other materials provided
+ *       with the distribution.
+ *     * Neither the name of Code Aurora Forum, Inc. nor the names of its
+ *       contributors may be used to endorse or promote products derived
+ *       from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include<dev/pm8921_leds.h>
+#include<dev/pm8921.h>
+
+void led_tests()
+{
+uint32_t duty_us, period_us;
+
+    /* 50% Duty cycle */
+    duty_us = 500000;
+    period_us = 1000000;
+
+    /* Configure PM8921_ID_LED_0 from PWM2*/
+    pm8921_config_led_current(PM8921_ID_LED_0, 2, PWM2, 1);
+
+    /* PWM2 for PM8921_ID_LED_0 is LPG 5
+     * Configure and enable lpg5
+     */
+    pm_set_pwm_config(5, duty_us, period_us, &pmic);
+    pm_pwm_channel_enable(5, &pmic);
+
+    /* Configure and enable lpg0 for  panel backlight*/
+    pm_set_pwm_config(0, duty_us, period_us, &pmic);
+    pm_pwm_channel_enable(0, &pmic);
+
+    mdelay(10000);
+
+    /* Configure PM8921_ID_LED_1 also from PWM2*/
+    pm8921_config_led_current(PM8921_ID_LED_1, 2, PWM2, 1);
+    mdelay(10000);
+
+    /* Disable PM8921_ID_LED_0 */
+    pm8921_config_led_current(PM8921_ID_LED_0, 2, 2, 0);
+
+    /* Turn on GPIO 24 through LPG 0
+     * Will be reconfigured during display_init
+     */
+    panel_backlight_on_pwm();
+
+    mdelay(10000);
+
+    /* Disable PM8921_ID_LED_1 */
+    pm8921_config_led_current(PM8921_ID_LED_1, 2, 2, 0);
+}

+ 90 - 0
app/tests/printf_tests.c

@@ -0,0 +1,90 @@
+/*
+ * Copyright (c) 2008 Travis Geiselbrecht
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files
+ * (the "Software"), to deal in the Software without restriction,
+ * including without limitation the rights to use, copy, modify, merge,
+ * publish, distribute, sublicense, and/or sell copies of the Software,
+ * and to permit persons to whom the Software is furnished to do so,
+ * subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+ * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+#include <app/tests.h>
+#include <debug.h>
+
+void printf_tests(void)
+{
+	printf("printf tests\n");
+
+	printf("numbers:\n");
+	printf("int8:  %hhd %hhd %hhd\n", -12, 0, 254);
+	printf("uint8: %hhu %hhu %hhu\n", -12, 0, 254);
+	printf("int16: %hd %hd %hd\n", -1234, 0, 1234);
+	printf("uint16:%hu %hu %hu\n", -1234, 0, 1234);
+	printf("int:   %d %d %d\n", -12345678, 0, 12345678);
+	printf("uint:  %u %u %u\n", -12345678, 0, 12345678);
+	printf("long:  %ld %ld %ld\n", -12345678, 0, 12345678);
+	printf("ulong: %lu %lu %lu\n", -12345678, 0, 12345678);
+	printf("long:  %D %D %D\n", -12345678, 0, 12345678);
+	printf("ulong: %U %U %U\n", -12345678, 0, 12345678);
+	printf("longlong: %lli %lli %lli\n", -12345678LL, 0LL, 12345678LL);
+	printf("ulonglong: %llu %llu %llu\n", -12345678LL, 0LL, 12345678LL);
+	printf("size_t: %zd %zd %zd\n", -12345678, 0, 12345678);
+	printf("usize_t: %zu %zu %zu\n", -12345678, 0, 12345678);
+
+	printf("hex:\n");
+	printf("uint8: %hhx %hhx %hhx\n", -12, 0, 254);
+	printf("uint16:%hx %hx %hx\n", -1234, 0, 1234);
+	printf("uint:  %x %x %x\n", -12345678, 0, 12345678);
+	printf("ulong: %lx %lx %lx\n", -12345678, 0, 12345678);
+	printf("ulong: %X %X %X\n", -12345678, 0, 12345678);
+	printf("ulonglong: %llx %llx %llx\n", -12345678LL, 0LL, 12345678LL);
+	printf("usize_t: %zx %zx %zx\n", -12345678, 0, 12345678);
+
+	printf("alt/sign:\n");
+	printf("uint: %#x %#X\n", 0xabcdef, 0xabcdef);
+	printf("int: %+d %+d\n", 12345678, -12345678);
+
+	printf("formatting\n");
+	printf("int: a%8da\n", 12345678);
+	printf("int: a%9da\n", 12345678);
+	printf("int: a%-9da\n", 12345678);
+	printf("int: a%10da\n", 12345678);
+	printf("int: a%-10da\n", 12345678);
+	printf("int: a%09da\n", 12345678);
+	printf("int: a%010da\n", 12345678);
+	printf("int: a%6da\n", 12345678);
+
+	printf("a%1sa\n", "b");
+	printf("a%9sa\n", "b");
+	printf("a%-9sa\n", "b");
+	printf("a%5sa\n", "thisisatest");
+
+	int err;
+
+	err = printf("a");
+	printf(" returned %d\n", err);
+	err = printf("ab");
+	printf(" returned %d\n", err);
+	err = printf("abc");
+	printf(" returned %d\n", err);
+	err = printf("abcd");
+	printf(" returned %d\n", err);
+	err = printf("abcde");
+	printf(" returned %d\n", err);
+	err = printf("abcdef");
+	printf(" returned %d\n", err);
+}
+
+

+ 8 - 0
app/tests/rules.mk

@@ -0,0 +1,8 @@
+LOCAL_DIR := $(GET_LOCAL_DIR)
+
+INCLUDES += -I$(LOCAL_DIR)/include
+
+OBJS += \
+	$(LOCAL_DIR)/tests.o \
+	$(LOCAL_DIR)/thread_tests.o \
+	$(LOCAL_DIR)/printf_tests.o

+ 46 - 0
app/tests/tests.c

@@ -0,0 +1,46 @@
+/*
+ * Copyright (c) 2008 Travis Geiselbrecht
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files
+ * (the "Software"), to deal in the Software without restriction,
+ * including without limitation the rights to use, copy, modify, merge,
+ * publish, distribute, sublicense, and/or sell copies of the Software,
+ * and to permit persons to whom the Software is furnished to do so,
+ * subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+ * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+#include <app.h>
+#include <debug.h>
+#include <app/tests.h>
+#include <compiler.h>
+
+#if defined(WITH_LIB_CONSOLE)
+#include <lib/console.h>
+
+STATIC_COMMAND_START
+STATIC_COMMAND("printf_tests", NULL, (console_cmd)&printf_tests)
+STATIC_COMMAND("thread_tests", NULL, (console_cmd)&thread_tests)
+STATIC_COMMAND_END(tests);
+
+#endif
+
+static void tests_init(const struct app_descriptor *app)
+{
+}
+
+APP_START(tests)
+	.init = tests_init,
+	.flags = 0,
+APP_END
+

+ 322 - 0
app/tests/thread_tests.c

@@ -0,0 +1,322 @@
+/*
+ * Copyright (c) 2008 Travis Geiselbrecht
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files
+ * (the "Software"), to deal in the Software without restriction,
+ * including without limitation the rights to use, copy, modify, merge,
+ * publish, distribute, sublicense, and/or sell copies of the Software,
+ * and to permit persons to whom the Software is furnished to do so,
+ * subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+ * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+#include <debug.h>
+#include <rand.h>
+#include <app/tests.h>
+#include <kernel/thread.h>
+#include <kernel/mutex.h>
+#include <kernel/event.h>
+
+static int sleep_thread(void *arg)
+{
+	for(;;) {
+		printf("sleeper %p\n", current_thread);
+		thread_sleep(rand() % 500);
+	}
+	return 0;
+}
+
+int sleep_test(void)
+{
+	int i;
+	for(i=0; i < 16; i++)
+		thread_resume(thread_create("sleeper", &sleep_thread, NULL, DEFAULT_PRIORITY, DEFAULT_STACK_SIZE));
+	return 0;
+}
+
+static volatile int shared = 0;
+static mutex_t m;
+static volatile int mutex_thread_count = 0;
+
+static int mutex_thread(void *arg)
+{
+	int i;
+	const int iterations = 10000;
+
+	atomic_add(&mutex_thread_count, 1);
+
+	printf("mutex tester thread %p starting up, will go for %d iterations\n", current_thread, iterations);
+
+	for (i = 0; i < iterations; i++) {
+		mutex_acquire(&m);
+
+		if (shared != 0)
+			panic("someone else has messed with the shared data\n");
+
+		shared = (int)current_thread;
+		thread_yield();
+		shared = 0;
+
+		mutex_release(&m);
+		thread_yield();
+	}
+	atomic_add(&mutex_thread_count, -1);
+
+	return 0;
+}
+
+static int mutex_timeout_thread(void *arg)
+{
+	mutex_t *timeout_mutex = (mutex_t *)arg;
+	status_t err;
+
+	printf("mutex_timeout_thread acquiring mutex %p with 1 second timeout\n", timeout_mutex);
+	err = mutex_acquire_timeout(timeout_mutex, 1000);
+	printf("mutex_acquire_timeout returns %d\n", err);
+
+	return err;
+}
+
+static int mutex_zerotimeout_thread(void *arg)
+{
+	mutex_t *timeout_mutex = (mutex_t *)arg;
+	status_t err;
+
+	printf("mutex_zerotimeout_thread acquiring mutex %p with zero second timeout\n", timeout_mutex);
+	err = mutex_acquire_timeout(timeout_mutex, 0);
+	printf("mutex_acquire_timeout returns %d\n", err);
+
+	return err;
+}
+
+int mutex_test(void)
+{
+	mutex_init(&m);
+
+	int i;
+	for(i=0; i < 5; i++)
+		thread_resume(thread_create("mutex tester", &mutex_thread, NULL, DEFAULT_PRIORITY, DEFAULT_STACK_SIZE));
+
+	thread_sleep(1000);
+
+	while (mutex_thread_count > 0)
+		thread_yield();
+
+	printf("done with simple mutex tests\n");
+
+	printf("testing mutex timeout\n");
+
+	mutex_t timeout_mutex;
+
+	mutex_init(&timeout_mutex);
+	mutex_acquire(&timeout_mutex);
+
+	for (i=0; i < 2; i++)
+		thread_resume(thread_create("mutex timeout tester", &mutex_timeout_thread, (void *)&timeout_mutex, DEFAULT_PRIORITY, DEFAULT_STACK_SIZE));
+	for (i=0; i < 2; i++)
+		thread_resume(thread_create("mutex timeout tester", &mutex_zerotimeout_thread, (void *)&timeout_mutex, DEFAULT_PRIORITY, DEFAULT_STACK_SIZE));
+
+	thread_sleep(5000);
+	mutex_release(&timeout_mutex);
+
+	printf("done with mutex tests\n");
+
+	mutex_destroy(&timeout_mutex);
+
+	return 0;
+}
+
+static event_t e;
+
+static int event_signaller(void *arg)
+{
+	printf("event signaller pausing\n");
+	thread_sleep(1000);
+
+//	for (;;) {
+		printf("signalling event\n");
+		event_signal(&e, true);
+		printf("done signalling event\n");
+		thread_yield();
+//	}
+
+	return 0;
+}
+
+static int event_waiter(void *arg)
+{
+	printf("event waiter starting\n");
+
+	for (;;) {
+		printf("%p: waiting on event...\n", current_thread);
+		if (event_wait(&e) < 0) {
+			printf("%p: event_wait() returned error\n", current_thread);
+			return -1;
+		}
+		printf("%p: done waiting on event...\n", current_thread);
+		thread_yield();
+	}
+
+	return 0;
+}
+
+void event_test(void)
+{
+	/* make sure signalling the event wakes up all the threads */
+	event_init(&e, false, 0);
+	thread_resume(thread_create("event signaller", &event_signaller, NULL, DEFAULT_PRIORITY, DEFAULT_STACK_SIZE));
+	thread_resume(thread_create("event waiter 0", &event_waiter, NULL, DEFAULT_PRIORITY, DEFAULT_STACK_SIZE));
+	thread_resume(thread_create("event waiter 1", &event_waiter, NULL, DEFAULT_PRIORITY, DEFAULT_STACK_SIZE));
+	thread_resume(thread_create("event waiter 2", &event_waiter, NULL, DEFAULT_PRIORITY, DEFAULT_STACK_SIZE));
+	thread_resume(thread_create("event waiter 3", &event_waiter, NULL, DEFAULT_PRIORITY, DEFAULT_STACK_SIZE));
+	thread_sleep(2000);
+	event_destroy(&e);
+
+	/* make sure signalling the event wakes up precisely one thread */
+	event_init(&e, false, EVENT_FLAG_AUTOUNSIGNAL);
+	thread_resume(thread_create("event signaller", &event_signaller, NULL, DEFAULT_PRIORITY, DEFAULT_STACK_SIZE));
+	thread_resume(thread_create("event waiter 0", &event_waiter, NULL, DEFAULT_PRIORITY, DEFAULT_STACK_SIZE));
+	thread_resume(thread_create("event waiter 1", &event_waiter, NULL, DEFAULT_PRIORITY, DEFAULT_STACK_SIZE));
+	thread_resume(thread_create("event waiter 2", &event_waiter, NULL, DEFAULT_PRIORITY, DEFAULT_STACK_SIZE));
+	thread_resume(thread_create("event waiter 3", &event_waiter, NULL, DEFAULT_PRIORITY, DEFAULT_STACK_SIZE));
+	thread_sleep(2000);
+	event_destroy(&e);
+}
+
+static int quantum_tester(void *arg)
+{
+	for (;;) {
+		printf("%p: in this thread. rq %d\n", current_thread, current_thread->remaining_quantum);
+	}
+	return 0;
+}
+
+void quantum_test(void)
+{
+	thread_resume(thread_create("quantum tester 0", &quantum_tester, NULL, DEFAULT_PRIORITY, DEFAULT_STACK_SIZE));
+	thread_resume(thread_create("quantum tester 1", &quantum_tester, NULL, DEFAULT_PRIORITY, DEFAULT_STACK_SIZE));
+	thread_resume(thread_create("quantum tester 2", &quantum_tester, NULL, DEFAULT_PRIORITY, DEFAULT_STACK_SIZE));
+	thread_resume(thread_create("quantum tester 3", &quantum_tester, NULL, DEFAULT_PRIORITY, DEFAULT_STACK_SIZE));
+}
+
+static event_t context_switch_event;
+static event_t context_switch_done_event;
+
+static int context_switch_tester(void *arg)
+{
+	int i;
+	uint total_count = 0;
+	const int iter = 100000;
+	int thread_count = (int)arg;
+
+	event_wait(&context_switch_event);
+
+	uint count = arch_cycle_count();
+	for (i = 0; i < iter; i++) {
+		thread_yield();
+	}
+	total_count += arch_cycle_count() - count;
+	thread_sleep(1000);
+	printf("took %u cycles to yield %d times, %u per yield, %u per yield per thread\n", 
+		total_count, iter, total_count / iter, total_count / iter / thread_count);
+
+	event_signal(&context_switch_done_event, true);
+
+	return 0;
+}
+
+void context_switch_test(void)
+{
+	event_init(&context_switch_event, false, 0);
+	event_init(&context_switch_done_event, false, 0);
+
+	thread_resume(thread_create("context switch idle", &context_switch_tester, (void *)1, DEFAULT_PRIORITY, DEFAULT_STACK_SIZE));
+	thread_sleep(100);
+	event_signal(&context_switch_event, true);
+	event_wait(&context_switch_done_event);
+	thread_sleep(100);
+
+	event_unsignal(&context_switch_event);
+	event_unsignal(&context_switch_done_event);
+	thread_resume(thread_create("context switch 2a", &context_switch_tester, (void *)2, DEFAULT_PRIORITY, DEFAULT_STACK_SIZE));
+	thread_resume(thread_create("context switch 2b", &context_switch_tester, (void *)2, DEFAULT_PRIORITY, DEFAULT_STACK_SIZE));
+	thread_sleep(100);
+	event_signal(&context_switch_event, true);
+	event_wait(&context_switch_done_event);
+	thread_sleep(100);
+
+	event_unsignal(&context_switch_event);
+	event_unsignal(&context_switch_done_event);
+	thread_resume(thread_create("context switch 4a", &context_switch_tester, (void *)4, DEFAULT_PRIORITY, DEFAULT_STACK_SIZE));
+	thread_resume(thread_create("context switch 4b", &context_switch_tester, (void *)4, DEFAULT_PRIORITY, DEFAULT_STACK_SIZE));
+	thread_resume(thread_create("context switch 4c", &context_switch_tester, (void *)4, DEFAULT_PRIORITY, DEFAULT_STACK_SIZE));
+	thread_resume(thread_create("context switch 4d", &context_switch_tester, (void *)4, DEFAULT_PRIORITY, DEFAULT_STACK_SIZE));
+	thread_sleep(100);
+	event_signal(&context_switch_event, true);
+	event_wait(&context_switch_done_event);
+	thread_sleep(100);
+}
+
+static volatile int atomic;
+static volatile int atomic_count;
+
+static int atomic_tester(void *arg)
+{
+	int add = (int)arg;
+	int i;
+
+	TRACEF("add %d\n", add);
+
+	for (i=0; i < 1000000; i++) {
+		atomic_add(&atomic, add);
+	}
+
+	int old = atomic_add(&atomic_count, -1);
+	TRACEF("exiting, old count %d\n", old);
+
+	return 0;
+}
+
+static void atomic_test(void)
+{
+	atomic = 0;
+	atomic_count = 8;
+
+	thread_resume(thread_create("atomic tester 1", &atomic_tester, (void *)1, LOW_PRIORITY, DEFAULT_STACK_SIZE));
+	thread_resume(thread_create("atomic tester 1", &atomic_tester, (void *)1, LOW_PRIORITY, DEFAULT_STACK_SIZE));
+	thread_resume(thread_create("atomic tester 1", &atomic_tester, (void *)1, LOW_PRIORITY, DEFAULT_STACK_SIZE));
+	thread_resume(thread_create("atomic tester 1", &atomic_tester, (void *)1, LOW_PRIORITY, DEFAULT_STACK_SIZE));
+	thread_resume(thread_create("atomic tester 2", &atomic_tester, (void *)-1, LOW_PRIORITY, DEFAULT_STACK_SIZE));
+	thread_resume(thread_create("atomic tester 2", &atomic_tester, (void *)-1, LOW_PRIORITY, DEFAULT_STACK_SIZE));
+	thread_resume(thread_create("atomic tester 2", &atomic_tester, (void *)-1, LOW_PRIORITY, DEFAULT_STACK_SIZE));
+	thread_resume(thread_create("atomic tester 2", &atomic_tester, (void *)-1, LOW_PRIORITY, DEFAULT_STACK_SIZE));
+
+	while (atomic_count > 0) {
+		thread_sleep(1);
+	}
+
+	printf("atomic count == %d (should be zero)\n", atomic);
+}
+
+int thread_tests(void) 
+{
+	mutex_test();
+	event_test();
+
+	thread_sleep(200);
+	context_switch_test();
+
+	atomic_test();
+	
+	return 0;
+}

+ 144 - 0
arch/arm/arch.c

@@ -0,0 +1,144 @@
+/*
+ * Copyright (c) 2008 Travis Geiselbrecht
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files
+ * (the "Software"), to deal in the Software without restriction,
+ * including without limitation the rights to use, copy, modify, merge,
+ * publish, distribute, sublicense, and/or sell copies of the Software,
+ * and to permit persons to whom the Software is furnished to do so,
+ * subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+ * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+#include <debug.h>
+#include <arch.h>
+#include <arch/ops.h>
+#include <arch/arm.h>
+#include <arch/arm/mmu.h>
+#include <platform.h>
+#ifdef MTK_FORCE_CLUSTER1
+#include <platform/boot_mode.h>
+#endif
+
+extern void isb(void);
+extern void dsb(void);
+
+#if ARM_ISA_ARMV7
+static void set_vector_base(addr_t addr)
+{
+	__asm__ volatile("mcr	p15, 0, %0, c12, c0, 0" :: "r" (addr));
+}
+#endif
+
+void arch_early_init(void)
+{
+	/* turn off the cache */
+	arch_disable_cache(UCACHE);
+#ifdef ENABLE_L2_SHARING
+	config_L2_size();
+#endif
+
+#ifdef MTK_FORCE_CLUSTER1
+	if (mt_get_chip_sw_ver() < CHIP_SW_VER_02) {
+		/* set L2 data latency to 1 */
+		uint32_t tmp;
+		__asm__ volatile("mrc p15, 1, %0, c9, c0, 2" : "=r" (tmp));
+		tmp &= 0xfffc0000;
+		tmp |= 0x9251;
+		isb();
+		dsb();
+		__asm__ volatile("mcr p15, 1, %0, c9, c0, 2" :: "r" (tmp));
+		dsb();
+		isb();
+	}
+#endif
+
+	/* set the vector base to our exception vectors so we dont need to double map at 0 */
+#if ARM_ISA_ARMV7
+	set_vector_base(MEMBASE);
+#endif
+
+#if ARM_WITH_MMU
+#ifdef MTK_3LEVEL_PAGETABLE
+	platform_init_mmu();
+#else	//!MTK_3LEVEL_PAGETABLE
+#ifndef MTK_LM_MODE
+	platform_init_mmu_mappings();
+#else
+	platform_init_mmu();
+#endif
+#endif	//MTK_3LEVEL_PAGETABLE
+#endif
+
+	/* turn the cache back on */
+	arch_enable_cache(UCACHE);
+
+#ifdef HAVE_CACHE_PL310
+	arch_enable_l2cache();
+#endif
+
+#if ARM_WITH_NEON
+	/* enable cp10 and cp11 */
+	uint32_t val;
+	__asm__ volatile("mrc	p15, 0, %0, c1, c0, 2" : "=r" (val));
+	val |= (3<<22)|(3<<20);
+	__asm__ volatile("mcr	p15, 0, %0, c1, c0, 2" :: "r" (val));
+
+	/* set enable bit in fpexc */
+	__asm__ volatile("mrc  p10, 7, %0, c8, c0, 0" : "=r" (val));
+	val |= (1<<30);
+	__asm__ volatile("mcr  p10, 7, %0, c8, c0, 0" :: "r" (val));
+#endif
+
+#if 0
+#if ARM_ISA_ARMV7
+	/* enable the cycle count register */
+	uint32_t en;
+	__asm__ volatile("mrc	p15, 0, %0, c9, c12, 0" : "=r" (en));
+	en &= ~(1<<3); /* cycle count every cycle */
+	en |= 1; /* enable all performance counters */
+	__asm__ volatile("mcr	p15, 0, %0, c9, c12, 0" :: "r" (en));
+
+	/* enable cycle counter */
+	en = (1<<31);
+	__asm__ volatile("mcr	p15, 0, %0, c9, c12, 1" :: "r" (en));
+#endif
+#endif
+}
+
+void arch_init(void)
+{
+}
+
+void arch_uninit(void)
+{
+#if ARM_WITH_NEON
+	uint32_t val;
+	/* set disable bit in fpexc */
+	__asm__ volatile("mrc  p10, 7, %0, c8, c0, 0" : "=r" (val));
+	val &= ~(1<<30);
+	__asm__ volatile("mcr  p10, 7, %0, c8, c0, 0" :: "r" (val));
+
+	/* disable cp10 and cp11 */
+	__asm__ volatile("mrc	p15, 0, %0, c1, c0, 2" : "=r" (val));
+	val &= ~((3<<22)|(3<<20));
+	__asm__ volatile("mcr	p15, 0, %0, c1, c0, 2" :: "r" (val));
+#endif
+
+#if ARM_WITH_CP15
+	/* disable alignment faults */
+	arm_write_cr1(arm_read_cr1() & ~(0x1<<1));
+	dsb();
+#endif
+}
+

+ 98 - 0
arch/arm/asm.S

@@ -0,0 +1,98 @@
+/*
+ * Copyright (c) 2008 Travis Geiselbrecht
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files
+ * (the "Software"), to deal in the Software without restriction,
+ * including without limitation the rights to use, copy, modify, merge,
+ * publish, distribute, sublicense, and/or sell copies of the Software,
+ * and to permit persons to whom the Software is furnished to do so,
+ * subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+ * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+#include <asm.h>
+
+
+	/* context switch frame is as follows:
+	 * ulr
+	 * usp
+	 * lr
+	 * r11
+	 * r10
+	 * r9
+	 * r8
+	 * r7
+	 * r6
+	 * r5
+	 * r4
+	 */
+/* arm_context_switch(addr_t *old_sp, addr_t new_sp) */
+FUNCTION(arm_context_switch)
+	/* save all the usual registers + user regs */
+	/* the spsr is saved and restored in the iframe by exceptions.S */
+	sub		r3, sp, #(11*4)		/* can't use sp in user mode stm */
+	mov		r12, lr
+	stmia	r3, { r4-r11, r12, r13, r14 }^
+	
+	/* save old sp */
+	str		r3, [r0] 
+
+	/* clear any exlusive locks that the old thread holds */
+#if ARM_ISA_ARMV7
+	/* can clear it directly */
+	.word	0xf57ff01f // clrex
+#elif ARM_ISA_ARMV6
+	/* have to do a fake strex to clear it */
+	ldr		r0, =strex_spot
+	strex	r3, r2, [r0]
+#endif
+
+	/* load new regs */
+	ldmia	r1, { r4-r11, r12, r13, r14 }^
+	mov		lr, r12				/* restore lr */
+	add		sp, r1, #(11*4)     /* restore sp */
+	bx		lr
+
+.ltorg
+
+FUNCTION(arm_save_mode_regs)
+	mrs		r1, cpsr
+
+	cps		#0x11			/* fiq */
+	str		r13, [r0], #4
+	str		r14, [r0], #4
+	cps		#0x12			/* irq */
+	str		r13, [r0], #4
+	str		r14, [r0], #4
+	cps		#0x13			/* svc */
+	str		r13, [r0], #4
+	str		r14, [r0], #4
+	cps		#0x17			/* abt */
+	str		r13, [r0], #4
+	str		r14, [r0], #4
+	cps		#0x1b			/* und */
+	str		r13, [r0], #4
+	str		r14, [r0], #4
+	cps		#0x1f			/* sys */
+	str		r13, [r0], #4
+	str		r14, [r0], #4
+	
+	msr		cpsr_c, r1
+
+	bx		lr
+
+.data
+strex_spot:
+	.word	0
+	
+

+ 411 - 0
arch/arm/cache-ops.S

@@ -0,0 +1,411 @@
+/*
+ * Copyright (c) 2008 Travis Geiselbrecht
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files
+ * (the "Software"), to deal in the Software without restriction,
+ * including without limitation the rights to use, copy, modify, merge,
+ * publish, distribute, sublicense, and/or sell copies of the Software,
+ * and to permit persons to whom the Software is furnished to do so,
+ * subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+ * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+#include <asm.h>
+#include <arch/ops.h>
+#include <arch/defines.h>
+
+.text
+
+#if ARM_WITH_CACHE
+
+/* low level cache routines for various cpu families */
+
+#if ARM_CPU_ARM1136 || ARM_CPU_ARM926
+
+/* void arch_disable_cache(uint flags) */
+FUNCTION(arch_disable_cache)
+	mov		r12, #0						// zero register
+	mrs		r3, cpsr					// save the old interrupt state
+#if ARM_ISA_ARMv6
+	.word	0xf10c01c0	/* cpsid iaf */	// interrupts disabled
+#else
+	orr		r3, r3, #(1<<7)
+	msr		cpsr, r3
+#endif
+
+.Ldcache_disable:
+	tst		r0, #DCACHE
+	beq		.Licache_disable
+	mrc     p15, 0, r1, c1, c0, 0		// cr1
+	tst		r1, #(1<<2)					// is the dcache already disabled?
+	beq		.Licache_disable
+
+	bic		r1, #(1<<2)
+	mcr		p15, 0, r1, c1, c0, 0		// disable dcache
+
+#if ARM_CPU_ARM1136
+    mcr     p15, 0, r12, c7, c14, 0     // clean & invalidate dcache
+#elif ARM_CPU_ARM926
+0:
+	mrc		p15, 0, r15, c7, c14, 3		// clean & invalidate dcache
+	bne		0b
+#else
+#error whut?
+#endif
+	mcr		p15, 0, r0, c7, c10, 4		// data sync barrier (formerly drain write buffer)
+
+.Licache_disable:
+	tst		r0, #ICACHE
+	beq		.Ldone_disable
+
+	mrc     p15, 0, r1, c1, c0, 0		// cr1
+	bic		r1, #(1<<12)
+	mcr		p15, 0, r1, c1, c0, 0		// disable icache
+
+	mcr		p15, 0, r12, c7, c5, 0		// invalidate icache
+
+.Ldone_disable:
+	msr		cpsr, r3
+	bx		lr
+
+/* void arch_enable_cache(uint flags) */
+FUNCTION(arch_enable_cache)
+	mov		r12, #0						// zero register
+	mrs		r3, cpsr					// save the old interrupt state
+#if ARM_ISA_ARMv6
+	.word	0xf10c01c0	/* cpsid iaf */	// interrupts disabled
+#else
+	orr		r3, r3, #(1<<7)
+	msr		cpsr, r3
+#endif
+
+.Ldcache_enable:
+	tst		r0, #DCACHE
+	beq		.Licache_enable
+	mrc     p15, 0, r1, c1, c0, 0		// cr1
+	tst		r1, #(1<<2)					// is the dcache already enabled?
+	bne		.Licache_enable
+
+    mcr     p15, 0, r12, c7, c6, 0      // invalidate dcache
+
+	orr		r1, #(1<<2)
+	mcr		p15, 0, r1, c1, c0, 0		// enable dcache
+
+.Licache_enable:
+	tst		r0, #ICACHE
+	beq		.Ldone_enable
+
+	mcr		p15, 0, r12, c7, c5, 0		// invalidate icache
+
+	mrc     p15, 0, r1, c1, c0, 0		// cr1
+	orr		r1, #(1<<12)
+	mcr		p15, 0, r1, c1, c0, 0		// enable icache
+
+.Ldone_enable:
+	msr		cpsr, r3
+	bx		lr
+
+#elif ARM_ISA_ARMV7
+
+/* void arch_disable_cache(uint flags) */
+FUNCTION(arch_disable_cache)
+	stmfd	sp!, {r4-r11, lr}
+
+	mov		r7, r0						// save flags
+
+	mrs		r12, cpsr					// save the old interrupt state
+	.word	0xf10c01c0	/* cpsid iaf */	// interrupts disabled
+
+.Ldcache_disable:
+	tst		r7, #DCACHE
+	beq		.Licache_disable
+	mrc     p15, 0, r0, c1, c0, 0		// cr1
+	tst		r0, #(1<<2)					// is the dcache already disabled?
+	beq		.Ldcache_already_disabled
+
+	bic		r0, #(1<<2)
+	mcr		p15, 0, r0, c1, c0, 0		// disable dcache
+
+	// flush and invalidate the dcache
+	// NOTE: trashes a bunch of registers, can't be spilling stuff to the stack
+	bl		flush_invalidate_cache_v7
+
+	b		.Ldcache_disable_L2
+
+.Ldcache_already_disabled:
+	// make sure all of the caches are invalidated
+	// NOTE: trashes a bunch of registers, can't be spilling stuff to the stack
+	bl		invalidate_cache_v7
+
+.Ldcache_disable_L2:
+
+#if ARM_CPU_CORTEX_A9
+	// disable the L2, if present
+	mrc     p15, 0, r0, c1, c0, 1		// aux cr1
+	bic		r0, #(1<<1)
+	mcr		p15, 0, r0, c1, c0, 1		// disable L2 dcache
+#endif
+
+.Licache_disable:
+	tst		r7, #ICACHE
+	beq		.Ldone_disable
+
+	mrc     p15, 0, r0, c1, c0, 0		// cr1
+	bic		r0, #(1<<12)
+	mcr		p15, 0, r0, c1, c0, 0		// disable icache
+
+.Ldone_disable:
+	// make sure the icache is always invalidated
+	mov		r0, #0
+	mcr		p15, 0, r0, c7, c5, 0		// invalidate icache to PoU
+
+	msr		cpsr, r12
+	ldmfd	sp!, {r4-r11, pc}
+
+/* void arch_enable_cache(uint flags) */
+FUNCTION(arch_enable_cache)
+	stmfd	sp!, {r4-r11, lr}
+
+	mov		r7, r0						// save flags
+
+	mrs		r12, cpsr					// save the old interrupt state
+	.word	0xf10c01c0	/* cpsid iaf */	// interrupts disabled
+
+.Ldcache_enable:
+	tst		r7, #DCACHE
+	beq		.Licache_enable
+	mrc     p15, 0, r0, c1, c0, 0		// cr1
+	tst		r0, #(1<<2)					// is the dcache already enabled?
+	bne		.Licache_enable
+
+	// invalidate L1 and L2
+	// NOTE: trashes a bunch of registers, can't be spilling stuff to the stack
+	bl		invalidate_cache_v7
+
+#if ARM_CPU_CORTEX_A9
+	// enable the L2, if present
+	mrc     p15, 0, r0, c1, c0, 1		// aux cr1
+	orr		r0, #(1<<1)
+	mcr		p15, 0, r0, c1, c0, 1		// enable L2 dcache
+#endif
+
+	mrc     p15, 0, r0, c1, c0, 0		// cr1
+	orr		r0, #(1<<2)
+	mcr		p15, 0, r0, c1, c0, 0		// enable dcache
+
+.Licache_enable:
+	tst		r7, #ICACHE
+	beq		.Ldone_enable
+
+	mov		r0, #0
+	mcr		p15, 0, r0, c7, c5, 0		// invalidate icache to PoU
+
+	mrc     p15, 0, r0, c1, c0, 0		// cr1
+	orr		r0, #(1<<12)
+	mcr		p15, 0, r0, c1, c0, 0		// enable icache
+
+.Ldone_enable:
+	msr		cpsr, r12
+	ldmfd	sp!, {r4-r11, pc}
+
+// flush & invalidate cache routine, trashes r0-r6, r9-r11
+flush_invalidate_cache_v7:
+	/* from ARMv7 manual, B2-17 */
+	MRC 	p15, 1, R0, c0, c0, 1 		// Read CLIDR
+	ANDS 	R3, R0, #0x7000000
+	MOV 	R3, R3, LSR #23 			// Cache level value (naturally aligned)
+	BEQ 	.Lfinished
+	MOV 	R10, #0
+.Loop1:
+	ADD 	R2, R10, R10, LSR #1 		// Work out 3xcachelevel
+	MOV 	R1, R0, LSR R2 				// bottom 3 bits are the Cache type for this level
+	AND 	R1, R1, #7 					// get those 3 bits alone
+	CMP 	R1, #2
+	BLT 	.Lskip 						// no cache or only instruction cache at this level
+	MCR 	p15, 2, R10, c0, c0, 0 		// write the Cache Size selection register
+	.word	0xf57ff06f	// ISB 			// ISB to sync the change to the CacheSizeID reg
+	MRC 	p15, 1, R1, c0, c0, 0 		// reads current Cache Size ID register
+	AND 	R2, R1, #0x7 				// extract the line length field
+	ADD 	R2, R2, #4 					// add 4 for the line length offset (log2 16 bytes)
+	LDR 	R4, =0x3FF
+	ANDS 	R4, R4, R1, LSR #3 			// R4 is the max number on the way size (right aligned)
+	CLZ 	R5, R4 						// R5 is the bit position of the way size increment
+	LDR 	R6, =0x00007FFF
+	ANDS 	R6, R6, R1, LSR #13 		// R6 is the max number of the index size (right aligned)
+.Loop2:
+	MOV 	R9, R4 						// R9 working copy of the max way size (right aligned)
+.Loop3:
+	ORR 	R11, R10, R9, LSL R5 		// factor in the way number and cache number into R11
+	ORR 	R11, R11, R6, LSL R2 		// factor in the index number
+	MCR 	p15, 0, R11, c7, c14, 2 	// clean & invalidate by set/way
+	SUBS 	R9, R9, #1 					// decrement the way number
+	BGE 	.Loop3
+	SUBS 	R6, R6, #1 					// decrement the index
+	BGE 	.Loop2
+.Lskip:
+ 	ADD 	R10, R10, #2 					// increment the cache number
+	CMP 	R3, R10
+	BGT 	.Loop1
+
+.Lfinished:
+	mov		r10, #0
+	mcr		p15, 2, r10, c0, c0, 0		// select cache level 0
+	.word	0xf57ff06f	// isb
+
+	bx		lr
+
+// invalidate cache routine, trashes r0-r6, r9-r11
+invalidate_cache_v7:
+	/* from ARMv7 manual, B2-17 */
+	MRC 	p15, 1, R0, c0, c0, 1 		// Read CLIDR
+	ANDS 	R3, R0, #0x7000000
+	MOV 	R3, R3, LSR #23 			// Cache level value (naturally aligned)
+	BEQ 	.Lfinished_invalidate
+	MOV 	R10, #0
+.Loop1_invalidate:
+	ADD 	R2, R10, R10, LSR #1 		// Work out 3xcachelevel
+	MOV 	R1, R0, LSR R2 				// bottom 3 bits are the Cache type for this level
+	AND 	R1, R1, #7 					// get those 3 bits alone
+	CMP 	R1, #2
+	BLT 	.Lskip_invalidate 			// no cache or only instruction cache at this level
+	MCR 	p15, 2, R10, c0, c0, 0 		// write the Cache Size selection register
+	.word	0xf57ff06f	// ISB 			// ISB to sync the change to the CacheSizeID reg
+	MRC 	p15, 1, R1, c0, c0, 0 		// reads current Cache Size ID register
+	AND 	R2, R1, #0x7 				// extract the line length field
+	ADD 	R2, R2, #4 					// add 4 for the line length offset (log2 16 bytes)
+	LDR 	R4, =0x3FF
+	ANDS 	R4, R4, R1, LSR #3 			// R4 is the max number on the way size (right aligned)
+	CLZ 	R5, R4 						// R5 is the bit position of the way size increment
+	LDR 	R6, =0x00007FFF
+	ANDS 	R6, R6, R1, LSR #13 		// R6 is the max number of the index size (right aligned)
+.Loop2_invalidate:
+	MOV 	R9, R4 						// R9 working copy of the max way size (right aligned)
+.Loop3_invalidate:
+	ORR 	R11, R10, R9, LSL R5 		// factor in the way number and cache number into R11
+	ORR 	R11, R11, R6, LSL R2 		// factor in the index number
+	MCR 	p15, 0, R11, c7, c6, 2 		// invalidate by set/way
+	SUBS 	R9, R9, #1 					// decrement the way number
+	BGE 	.Loop3_invalidate
+	SUBS 	R6, R6, #1 					// decrement the index
+	BGE 	.Loop2_invalidate
+.Lskip_invalidate:
+ 	ADD 	R10, R10, #2 				// increment the cache number
+	CMP 	R3, R10
+	BGT 	.Loop1_invalidate
+
+.Lfinished_invalidate:
+	mov		r10, #0
+	mcr		p15, 2, r10, c0, c0, 0		// select cache level 0
+	.word	0xf57ff06f	// isb
+
+	bx		lr
+
+#else
+#error unhandled cpu
+#endif
+
+#if ARM_CPU_ARM926 || ARM_CPU_ARM1136 || ARM_CPU_CORTEX_A8 || ARM_CPU_CORTEX_A9 || ARM_CPU_CORTEX_A7 || ARM_CPU_CORTEX_A53
+/* shared cache flush routines */
+
+	/* void arch_flush_cache_range(addr_t start, size_t len); */
+FUNCTION(arch_clean_cache_range)
+#ifdef HAVE_CACHE_PL310
+	stmfd		sp!, {r4, r5, lr}
+	mov     	r4, r0
+	mov     	r5, r1
+#endif
+	add		r2, r0, r1			// get the end address
+	bic             r0, #(CACHE_LINE - 1)           // align the start address
+0:
+#ifdef  CONFIG_ARM_ERRATA_855873
+	mcr		p15, 0, r0, c7, c14, 1		// clean cache to PoC by MVA (DCCIMVAC )
+#else
+	mcr		p15, 0, r0, c7, c10, 1		// clean cache to PoC by MVA
+#endif
+	add		r0, r0, #CACHE_LINE
+	cmp		r0, r2
+	blo		0b
+
+	mov		r0, #0
+	mcr		p15, 0, r0, c7, c10, 4		// data sync barrier (formerly drain write buffer)
+
+	mov		r0, r4
+	mov		r1, r5
+#ifdef HAVE_CACHE_PL310
+	bl      	l2_clean_range
+	ldmfd   	sp!, {r4, r5, pc}
+#else
+	bx		lr
+#endif
+
+	/* void arch_flush_invalidate_cache_range(addr_t start, size_t len); */
+FUNCTION(arch_clean_invalidate_cache_range)
+#ifdef HAVE_CACHE_PL310
+	stmfd   	sp!, {r4, r5, lr}
+	mov     	r4, r0
+	mov     	r5, r1
+#endif
+        add             r2, r0, r1                      // get the end address
+        bic             r0, #(CACHE_LINE - 1)           // align the start address
+0:
+	mcr		p15, 0, r0, c7, c14, 1		// clean & invalidate cache to PoC by MVA
+	add		r0, r0, #CACHE_LINE
+	cmp		r0, r2
+	blo		0b
+
+	mov		r0, #0
+	mcr		p15, 0, r0, c7, c10, 4		// data sync barrier (formerly drain write buffer)
+	mov		r0, r4
+	mov		r1, r5
+#ifdef HAVE_CACHE_PL310
+	bl      l2_flush_range
+	ldmfd   sp!, {r4, r5, pc}
+#else
+	bx		lr
+#endif
+
+	/* void arch_sync_cache_range(addr_t start, size_t len); */
+FUNCTION(arch_sync_cache_range)
+	push    { r14 }
+	bl      arch_clean_cache_range
+
+	mov     r0, #0
+	mcr     p15, 0, r0, c7, c5, 0       // invalidate icache to PoU
+
+	pop     { pc }
+
+#else
+#error unhandled cpu
+#endif
+
+#else
+
+/* no cache */
+
+FUNCTION(arch_disable_cache)
+	bx		lr
+
+FUNCTION(arch_enable_cache)
+	bx		lr
+
+FUNCTION(arch_clean_cache_range)
+	bx		lr
+
+FUNCTION(arch_clean_invalidate_cache_range)
+	bx		lr
+
+FUNCTION(arch_sync_cache_range)
+	bx		lr
+
+#endif // ARM_WITH_CACHE
+

+ 133 - 0
arch/arm/cache.c

@@ -0,0 +1,133 @@
+/*
+ * Copyright (c) 2008 Travis Geiselbrecht
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files
+ * (the "Software"), to deal in the Software without restriction,
+ * including without limitation the rights to use, copy, modify, merge,
+ * publish, distribute, sublicense, and/or sell copies of the Software,
+ * and to permit persons to whom the Software is furnished to do so,
+ * subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+ * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+#include <kernel/thread.h> 
+#include <platform/mt_typedefs.h>
+#include <arch/arm/cache.h>
+#include <platform/mt_reg_base.h>
+
+volatile struct pl310_regs *PL310_L2CC = (struct pl310_regs *)0xC000E000;
+void dsb(void);
+static unsigned int way_mask;	
+
+static void l2_cache_sync(void)
+{
+	enter_critical_section();
+	PL310_L2CC->CacheSync = 0;
+	exit_critical_section();
+}
+
+static void l2_inv_all(void)
+{
+	/* invalidate all ways */
+	enter_critical_section();
+	PL310_L2CC->InvalidateByWay = way_mask;
+	while (PL310_L2CC->InvalidateByWay & way_mask);
+	PL310_L2CC->CacheSync = 0;
+	exit_critical_section();
+}
+
+
+void l2_clean_range(unsigned long start, unsigned long len)
+{
+	unsigned long end = start + len; 
+	
+	CACHE_ALLIGN(start);
+	
+	enter_critical_section();
+	
+	while (start < end) {
+			PL310_L2CC->CleanLineByPA = start;
+			start += CACHE_LINE_SIZE;
+	}
+	
+	PL310_L2CC->CacheSync = 0;
+	exit_critical_section();
+}
+
+void l2_flush_range(unsigned long start, unsigned long len)
+{
+	unsigned long end = start + len; 
+	CACHE_ALLIGN(start);
+	
+	enter_critical_section();
+	
+	PL310_L2CC->DebugControl = 0x3;
+	while (start < end) {		
+#if MACH_TYPE == 6575
+		PL310_L2CC->CleanLineByPA = start;
+		PL310_L2CC->InvalidateLineByPA = start;
+#else
+		PL310_L2CC->FlushLineByPA = start;
+#endif
+		start += CACHE_LINE_SIZE;
+	}
+	PL310_L2CC->DebugControl = 0x0;
+	
+	PL310_L2CC->CacheSync = 0;
+	exit_critical_section();
+}
+
+void l2_disable(void)
+{
+
+	// flush all 
+	PL310_L2CC->DebugControl = 0x3;
+	PL310_L2CC->FlushByWay = way_mask;
+	while (PL310_L2CC->FlushByWay & way_mask);	
+	PL310_L2CC->CacheSync = 0;
+	PL310_L2CC->DebugControl = 0x0;
+	
+	//disable l2
+	PL310_L2CC->Control = 0x0; 
+	dsb();
+
+}
+
+unsigned int get_num_ways(void)
+{
+	unsigned int aux_val;
+	unsigned int num_ways;
+	
+	aux_val = PL310_L2CC->AuxControl;
+
+	if (aux_val & (1 << 16))
+		num_ways = 16;
+	else
+		num_ways = 8;
+	return num_ways;
+}
+
+#define Auxiliary_VALUE  0x70000000
+void arch_enable_l2cache(void)
+{
+	PL310_L2CC->PowerControl = DYNAMIC_CLOCK_GATING_ENABLE;
+	PL310_L2CC->PrefetchControl = (PL310_L2CC->PrefetchControl) | 0x40000000 ;
+	PL310_L2CC->AuxControl = (PL310_L2CC->AuxControl & 0X8FFFFFFF) | Auxiliary_VALUE;
+	
+	way_mask = (1 << get_num_ways()) - 1;
+
+	l2_inv_all();
+
+	PL310_L2CC->Control = 0x1;
+}
+

Beberapa file tidak ditampilkan karena terlalu banyak file yang berubah dalam diff ini