Merge "QcomModulePkg: rename ffbm-02 string to qmmi for Qmmi mode"
diff --git a/BaseTools/Source/C/LzmaCompress/Sdk/C/LzmaEnc.c b/BaseTools/Source/C/LzmaCompress/Sdk/C/LzmaEnc.c
index 95c3c9f..98b1ca9 100644
--- a/BaseTools/Source/C/LzmaCompress/Sdk/C/LzmaEnc.c
+++ b/BaseTools/Source/C/LzmaCompress/Sdk/C/LzmaEnc.c
@@ -1372,7 +1372,7 @@
       if (repIndex == 0)

         startLen = lenTest + 1;

         

-      /* if (_maxMode) */

+      if (1 /* _maxMode */)

         {

           UInt32 lenTest2 = lenTest + 1;

           UInt32 limit = lenTest2 + p->numFastBytes;

diff --git a/QcomModulePkg/Application/LinuxLoader/LinuxLoader.c b/QcomModulePkg/Application/LinuxLoader/LinuxLoader.c
old mode 100644
new mode 100755
index 02dac0a..317b5b6
--- a/QcomModulePkg/Application/LinuxLoader/LinuxLoader.c
+++ b/QcomModulePkg/Application/LinuxLoader/LinuxLoader.c
@@ -2,7 +2,7 @@
  * Copyright (c) 2009, Google Inc.
  * All rights reserved.
  *
- * Copyright (c) 2009-2019, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2009-2020, The Linux Foundation. All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions are met:
@@ -42,6 +42,7 @@
 #include <Library/PartitionTableUpdate.h>
 #include <Library/ShutdownServices.h>
 #include <Library/StackCanary.h>
+#include "Library/ThreadStack.h"
 #include <Library/HypervisorMvCalls.h>
 #include <Library/UpdateCmdLine.h>
 
@@ -53,36 +54,7 @@
 STATIC BOOLEAN BootIntoFastboot = FALSE;
 STATIC BOOLEAN BootIntoRecovery = FALSE;
 
-STATIC VOID* UnSafeStackPtr;
-
-STATIC EFI_STATUS __attribute__ ( (no_sanitize ("safe-stack")))
-AllocateUnSafeStackPtr (VOID)
-{
-
-  EFI_STATUS Status = EFI_SUCCESS;
-
-  UnSafeStackPtr = AllocateZeroPool (BOOT_LOADER_MAX_UNSAFE_STACK_SIZE);
-  if (UnSafeStackPtr == NULL) {
-    DEBUG ((EFI_D_ERROR, "Failed to Allocate memory for UnSafeStack \n"));
-    Status = EFI_OUT_OF_RESOURCES;
-    return Status;
-  }
-
-  UnSafeStackPtr += BOOT_LOADER_MAX_UNSAFE_STACK_SIZE;
-
-  return Status;
-}
-
-//This function is to return the Unsafestack ptr address
-VOID** __attribute__ ( (no_sanitize ("safe-stack")))
-__safestack_pointer_address (VOID)
-{
-
-  return (VOID**) &UnSafeStackPtr;
-}
-
 // This function is used to Deactivate MDTP by entering recovery UI
-
 STATIC EFI_STATUS MdtpDisable (VOID)
 {
   BOOLEAN MdtpActive = FALSE;
@@ -176,7 +148,8 @@
   DEBUG ((EFI_D_VERBOSE, "LinuxLoaderEntry Address: 0x%llx\n",
          (UINTN)LinuxLoaderEntry));
 
-  Status = AllocateUnSafeStackPtr ();
+  Status = InitThreadUnsafeStack ();
+
   if (Status != EFI_SUCCESS) {
     DEBUG ((EFI_D_ERROR, "Unable to Allocate memory for Unsafe Stack: %r\n",
             Status));
@@ -318,5 +291,6 @@
 stack_guard_update_default:
   /*Update stack check guard with defualt value then return*/
   __stack_chk_guard = DEFAULT_STACK_CHK_GUARD;
+
   return Status;
 }
diff --git a/QcomModulePkg/Include/Library/Board.h b/QcomModulePkg/Include/Library/Board.h
index 6f82e63..62e30e6 100644
--- a/QcomModulePkg/Include/Library/Board.h
+++ b/QcomModulePkg/Include/Library/Board.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2015-2018, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2015-2018, 2020, The Linux Foundation. All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions are
@@ -47,6 +47,8 @@
 
 #define BIT(x) (1UL << x)
 
+extern RamPartitionEntry *RamPartitionEntries;
+
 typedef enum {
   EMMC = 0,
   UFS = 1,
@@ -54,12 +56,28 @@
   UNKNOWN,
 } MemCardType;
 
+#define DDR_SHIFT      8
+
+#define MB             (1024 * 1024UL)
+#define DDR_256MB      (256 * MB)
+#define DDR_512MB      (512 * MB)
+#define DDR_1024MB     (1024 * MB)
+#define DDR_2048MB     (2048 * MB)
+
+typedef enum {
+  DDRTYPE_256MB = 1,
+  DDRTYPE_512MB,
+  DDRTYPE_1024MB,
+  DDRTYPE_2048MB,
+} DdrType;
+
 struct BoardInfo {
   EFI_PLATFORMINFO_PLATFORM_INFO_TYPE PlatformInfo;
   UINT32 RawChipId;
   CHAR8 ChipBaseBand[EFICHIPINFO_MAX_ID_LENGTH];
   EFIChipInfoVersionType ChipVersion;
   EFIChipInfoFoundryIdType FoundryId;
+  UINT32 HlosSubType;
 };
 
 EFI_STATUS
@@ -93,8 +111,10 @@
 UfsGetSetBootLun (UINT32 *UfsBootlun, BOOLEAN IsGet);
 BOOLEAN BoardPlatformFusion (VOID);
 UINT32 BoardPlatformRawChipId (VOID);
-EFI_STATUS GetRamPartitions (RamPartitionEntry **RamPartitions,
+EFI_STATUS ReadRamPartitions (RamPartitionEntry **RamPartitions,
                   UINT32 *NumPartitions);
 EFI_STATUS GetGranuleSize (UINT32 *MinPasrGranuleSize);
 VOID GetPageSize (UINT32 *PageSize);
+EFI_STATUS BoardDdrType (UINT32 *Type);
+UINT32 BoardPlatformHlosSubType (VOID);
 #endif
diff --git a/QcomModulePkg/Include/Library/LocateDeviceTree.h b/QcomModulePkg/Include/Library/LocateDeviceTree.h
index b08120a..40f70b0 100644
--- a/QcomModulePkg/Include/Library/LocateDeviceTree.h
+++ b/QcomModulePkg/Include/Library/LocateDeviceTree.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2015, 2017-2019, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2015, 2017-2020, The Linux Foundation. All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions are
@@ -70,6 +70,8 @@
 #define PMIC_SHIFT_IDX (2)
 #define PLATFORM_SUBTYPE_SHIFT_ID (0x18)
 #define FOUNDRY_ID_MASK (0x00ff0000)
+#define PLATFORM_SUBTYPE_MASK (0x000000ff)
+#define DDR_MASK (0x00000700)
 
 typedef enum {
   NONE_MATCH,
@@ -99,6 +101,7 @@
   PMIC_MATCH_EXACT_MODEL_IDX3,
   SUBTYPE_DEFAULT_MATCH,
   SUBTYPE_EXACT_MATCH,
+  DDR_MATCH,
   VARIANT_MATCH,
   SOC_MATCH,
   MAX_MATCH,
@@ -213,6 +216,7 @@
 
 enum dt_entry_info {
   DTB_FOUNDRY = 0,
+  DTB_DDR,
   DTB_SOC,
   DTB_MAJOR_MINOR,
   DTB_PMIC0,
diff --git a/QcomModulePkg/Include/Library/ThreadStack.h b/QcomModulePkg/Include/Library/ThreadStack.h
new file mode 100755
index 0000000..1b12467
--- /dev/null
+++ b/QcomModulePkg/Include/Library/ThreadStack.h
@@ -0,0 +1,57 @@
+/*
+ * Copyright (c) 2020, The Linux Foundation. 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 Linux Foundation 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 __THREADSTACK_H__
+#define __THREADSTACK_H__
+
+#include "list.h"
+#include <Protocol/EFIKernelInterface.h>
+
+/* Stack address will change frequently, we need record the top adderss and
+ * free it at suitable place.
+ */
+typedef struct _THREAD_STACK_ENTRY {
+  Thread                      *Thread;
+  VOID                        *StackBottom;
+  VOID                        *StackTop;
+}THREAD_STACK_ENTRY;
+
+typedef struct _THREAD_LIST_TABLE {
+  struct list_node Node;
+  struct _THREAD_STACK_ENTRY   *ThreadStackEntry;
+}THREAD_STACK_NODE;
+
+EFI_STATUS __attribute__ ( (no_sanitize ("safe-stack")))
+AllocateUnSafeStackPtr (Thread* CurrentThread);
+VOID** __attribute__ ( (no_sanitize ("safe-stack")))
+__safestack_pointer_address (VOID);
+VOID ThreadStackNodeRemove (Thread* CurrentThread);
+VOID ThreadStackReleaseCb (VOID * Arg);
+EFI_STATUS InitThreadUnsafeStack (VOID);
+#endif
diff --git a/QcomModulePkg/Include/Protocol/EFIKernelInterface.h b/QcomModulePkg/Include/Protocol/EFIKernelInterface.h
new file mode 100755
index 0000000..b89fc1f
--- /dev/null
+++ b/QcomModulePkg/Include/Protocol/EFIKernelInterface.h
@@ -0,0 +1,657 @@
+/** @file
+ *
+ * UEFI Protocol interface for SMP scheduler services in UEFI
+ *
+ * Copyright (c) 2020 The Linux Foundation. All rights reserved.
+ *
+ * Portions Copyright (c) 2008-2015 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.
+ *
+ *
+**/
+
+/*=============================================================================
+                              EDIT HISTORY
+
+ when       who     what, where, why
+ --------   ---     -----------------------------------------------------------
+ 10/22/19   md      Added API's to support unsafe stack.
+ 01/15/19   yg      Add Thread/CPU stat API's
+ 09/15/18   yg      Add WDog interface
+ 02/21/18   yg      Updated to latest interface
+ 06/14/17   yg      Initial version
+
+=============================================================================*/
+
+#include <Uefi.h>
+
+#ifndef ___EFI_KERNEL_PROTOCOL_H__
+#define ___EFI_KERNEL_PROTOCOL_H__
+
+/* External global reference to the Kernel Protocol GUID */
+extern EFI_GUID gEfiKernelProtocolGuid;
+
+/* Protocol GUID definition. { B5062BE7-170B-4A32-BE21-689262FF4399 } */
+#define EFI_KERNEL_PROTOCOL_GUID \
+    { 0xB5062BE7, 0x170B, 0x4A32, { 0xBE, 0x21, 0x68, 0x92, 0x62, 0xFF, 0x43, \
+      0x99 } }
+
+/*
+ *   Document the version changes here
+ *   V 1.0
+ *      Initial version
+ *
+ *   V 1.1
+ *      Added API ConfigureInterrupt
+ *
+ *   V 1.2
+ *      Removed unsupported thread interface API's
+ *      Added Power transition notification registration API's
+ *
+ *   V 1.3
+ *      Added Watchdog interface
+ *
+ *   V 1.4
+ *      Added Thread level stats API, renamed the ThreadStats to CPU Stats to
+ *      correct the reference. Retained old API for backward compatibility
+ *      Added Lib version member.
+ *
+ *   V 1.5
+ *      Add Simple lock API's with recursive lock support
+ *
+ *   V 1.6
+ *      Add API's to support unsafe stack.
+ *
+ * */
+#define EFI_KERNEL_PROTOCOL_VER_INTR_CONFIG        0x00010001
+#define EFI_KERNEL_PROTOCOL_VER_PWR_NOTIFY         0x00010002
+#define EFI_KERNEL_PROTOCOL_VER_WDOG_INTF          0x00010003
+#define EFI_KERNEL_PROTOCOL_VER_THR_CPU_STATS      0x00010004
+#define EFI_KERNEL_PROTOCOL_VER_LIB_VER_API        0x00010004
+#define EFI_KERNEL_PROTOCOL_VER_LOCK_API           0x00010005
+#define EFI_KERNEL_PROTOCOL_VER_UNSAFE_STACK_APIS  0x00010006
+
+/* Current protocol version */
+#define EFI_KERNEL_PROTOCOL_VERSION    EFI_KERNEL_PROTOCOL_VER_UNSAFE_STACK_APIS
+
+/*******************************************************************************
+ *
+ *   Interface type definitions
+ *
+ ******************************************************************************/
+
+typedef INT32 KStatus;
+
+#define NO_ERROR                (0)
+#define ERR_GENERIC             (-1)
+#define ERR_NOT_FOUND           (-2)
+#define ERR_NOT_READY           (-3)
+#define ERR_NO_MSG              (-4)
+#define ERR_NO_MEMORY           (-5)
+#define ERR_ALREADY_STARTED     (-6)
+#define ERR_NOT_VALID           (-7)
+#define ERR_INVALID_ARGS        (-8)
+#define ERR_NOT_ENOUGH_BUFFER   (-9)
+#define ERR_NOT_SUSPENDED       (-10)
+#define ERR_OBJECT_DESTROYED    (-11)
+#define ERR_NOT_BLOCKED         (-12)
+#define ERR_TIMED_OUT           (-13)
+#define ERR_ALREADY_EXISTS      (-14)
+#define ERR_CHANNEL_CLOSED      (-15)
+#define ERR_OFFLINE             (-16)
+#define ERR_NOT_ALLOWED         (-17)
+#define ERR_BAD_PATH            (-18)
+#define ERR_ALREADY_MOUNTED     (-19)
+#define ERR_IO                  (-20)
+#define ERR_NOT_DIR             (-21)
+#define ERR_NOT_FILE            (-22)
+#define ERR_RECURSE_TOO_DEEP    (-23)
+#define ERR_NOT_SUPPORTED       (-24)
+#define ERR_TOO_BIG             (-25)
+#define ERR_CANCELLED           (-26)
+#define ERR_NOT_IMPLEMENTED     (-27)
+#define ERR_CHECKSUM_FAIL       (-28)
+#define ERR_CRC_FAIL            (-29)
+#define ERR_CMD_UNKNOWN         (-30)
+#define ERR_BAD_STATE           (-31)
+#define ERR_BAD_LEN             (-32)
+#define ERR_BUSY                (-33)
+#define ERR_THREAD_DETACHED     (-34)
+#define ERR_I2C_NACK            (-35)
+#define ERR_ALREADY_EXPIRED     (-36)
+#define ERR_OUT_OF_RANGE        (-37)
+#define ERR_NOT_CONFIGURED      (-38)
+#define ERR_NOT_MOUNTED         (-39)
+#define ERR_FAULT               (-40)
+#define ERR_NO_RESOURCES        (-41)
+#define ERR_BAD_HANDLE          (-42)
+#define ERR_ACCESS_DENIED       (-43)
+#define ERR_PARTIAL_WRITE       (-44)
+
+typedef struct
+{
+    UINT32 PreemptCount;
+    UINT32 BlockedCount;
+    UINT64 PreemptDuration;
+    UINT64 BlockedDuration;
+    UINT64 ActiveDuration;
+    UINT64 SleepDuration;
+}ThreadStats;
+
+typedef struct
+{
+    UINT64 IdleTime;
+    UINT64 LastIdleTimestamp;
+    UINT64 Reschedules;
+    UINT64 ContextSwitches;
+    UINT64 Preempts;
+    UINT64 Yields;
+    UINT64 Interrupts;    /* platform code increment this */
+    UINT64 TimerInts;     /* timer code increment this */
+    UINT64 Timers;        /* timer code increment this */
+    UINT64 RescheduleIpis;
+}CpuSchedStats;
+
+enum PwrTxnType{
+    DevicePwrNone    = 0,     // None
+    DevicePwrOFF     = 1,     // Turn the device power OFF
+    DevicePwrON      = 2,     // Turn the device power ON
+};
+
+typedef VOID (*UnsafeStackCb) (void* Arg);
+
+typedef struct {
+   VOID          *unsafe_sp_base; 
+   UINT64        unsafe_stack_size;
+   UnsafeStackCb cb;
+   VOID          *unsafe_stack_cb_data;
+   VOID          *unsafe_stack_top;
+}ThrUnsafeStackIntf;
+/******************************************************************************
+ *   Interrupt handler interface
+ *
+ *   Note that the interrupt handlers registered should not conflict with
+ *   scheduler registered interrupts for PPI, SGI and SPI interrupt vectors
+ *
+ *   Handlers execute in ISR context, so only events can be posted with some
+ *   restrictions.
+ *
+ ******************************************************************************/
+enum HandlerStatus
+{
+  HANDLER_NO_RESCHEDULE = 0,
+  HANDLER_RESCHEDULE
+};
+
+enum IntrConfig
+{
+   INTR_CONFIG_NONE             = 0,
+   INTR_CONFIG_EDGE_TRIGGER     = 1,
+   INTR_CONFIG_MAX              = 2,
+};
+
+typedef enum HandlerStatus (*IntrHandler)(VOID *Arg);
+
+typedef VOID (*REGISTER_INTR_HANDLER) (UINT32 Vector, IntrHandler Handler,
+    VOID *Arg);
+
+typedef KStatus (*MASK_INTERRUPT) (UINT32 Vector);
+typedef KStatus (*UNMASK_INTERRUPT) (UINT32 Vector);
+typedef KStatus (*CONFIGURE_INTERRUPT) (UINT32 Vector,
+    enum IntrConfig Config, VOID* Arg);
+
+typedef struct {
+  REGISTER_INTR_HANDLER    RegisterIntrHandler;
+  MASK_INTERRUPT           MaskInterrupt;
+  UNMASK_INTERRUPT         UnmaskInterrupt;
+  CONFIGURE_INTERRUPT      ConfigureInterrupt;
+} InterruptIntf;
+
+/******************************************************************************
+ *
+ *   Scheduler supported Event Services
+ *
+ ******************************************************************************/
+
+/* Rules for Events:
+ * - Events may be signaled from interrupt context *but* the reschedule
+ *     parameter must be false in that case.
+ * - Events may not be waited upon from interrupt context.
+ * - Events *without* FLAG_AUTOUNSIGNAL:
+ *   - Wake up any waiting threads when signaled.
+ *   - Continue to do so (no threads will wait) until unsignaled.
+ * - Events *with* FLAG_AUTOUNSIGNAL:
+ *   - If one or more threads are waiting when signaled, one thread will
+ *     be woken up and return.  The signaled state will not be set.
+ *   - If no threads are waiting when signaled, the Event will remain
+ *     in the signaled state until a thread attempts to wait (at which
+ *     time it will unsignal atomicly and return immediately) or
+ *     event_unsignal() is called.
+*/
+
+#define SCHED_EVENT_FLAG_AUTOUNSIGNAL             1
+
+#define SCHED_EVENT_STATE_UNSIGNALED              0
+#define SCHED_EVENT_STATE_SIGNALED                1
+
+struct event;
+typedef struct event Event;
+
+typedef UINT32 TimeDuration;
+
+#ifndef INFINITE_TIME
+#define INFINITE_TIME              0xFFFFFFFF
+#endif
+
+typedef Event* (*EVENT_INIT)(UINT64 Id OPTIONAL, _Bool Initial, UINT32 Flags);
+typedef VOID (*EVENT_DESTROY)(Event *);
+
+typedef _Bool (*EVENT_INITIALIZED)(Event *Evt);
+
+typedef KStatus (*EVENT_WAIT)(Event *Evt);
+typedef KStatus (*EVENT_WAIT_TIMEOUT)(Event *, TimeDuration);
+
+typedef KStatus (*EVENT_SIGNAL)(Event *, _Bool Reschedule);
+typedef KStatus (*EVENT_UNSIGNAL)(Event *Evt);
+
+typedef _Bool (*EVENT_GET_SIGNAL_STATE) (Event *Evt);
+
+typedef struct {
+  EVENT_INIT              EventInit;
+  EVENT_DESTROY           EventDestroy;
+  EVENT_INITIALIZED       EventInitialized;
+  EVENT_WAIT              EventWait;
+  EVENT_WAIT_TIMEOUT      EventWaitTimeout;
+  EVENT_SIGNAL            EventSignal;
+  EVENT_UNSIGNAL          EventUnsignal;
+  EVENT_GET_SIGNAL_STATE  EventGetSignalState;
+}EventIntf;
+
+/******************************************************************************
+     Mutex
+*******************************************************************************/
+/* Rules for Mutexes:
+ * - Mutexes are only safe to use from thread context.
+ * - Mutexes are non-recursive.
+*/
+struct mutex;
+typedef struct mutex Mutex;
+
+typedef Mutex* (*MUTEX_INIT)(UINT64 Id OPTIONAL);
+typedef VOID (*MUTEX_DESTROY)(Mutex *Mtx);
+
+typedef KStatus (*MUTEX_ACQUIRE)(Mutex *Mtx);
+/* try to acquire the mutex with a timeout value */
+typedef KStatus (*MUTEX_ACQUIRE_TIMEOUT)(Mutex *, TimeDuration);
+
+typedef KStatus (*MUTEX_RELEASE)(Mutex *Mtx);
+
+/* does the current thread hold the mutex? */
+typedef _Bool (*IS_MUTEX_HELD)(Mutex *Mtx);
+
+typedef struct {
+  MUTEX_INIT               MutexInit;
+  MUTEX_DESTROY            MutexDestroy;
+  MUTEX_ACQUIRE            MutexAcquire;
+  MUTEX_ACQUIRE_TIMEOUT    MutexAcquireTimeout;
+  MUTEX_RELEASE            MutexRelease;
+  IS_MUTEX_HELD            IsMutexHeld;
+
+}MutexIntf;
+
+/******************************************************************************
+     Semaphore
+******************************************************************************/
+struct semaphore;
+typedef struct semaphore Semaphore;
+
+typedef Semaphore* (*SEM_INIT)(UINT64 Id OPTIONAL, UINT32 Cnt);
+typedef VOID (*SEM_DESTROY)(Semaphore *);
+
+typedef INT32 (*SEM_POST)(Semaphore *, _Bool Resched);
+typedef KStatus (*SEM_WAIT)(Semaphore *);
+typedef KStatus (*SEM_TRYWAIT)(Semaphore *);
+typedef KStatus (*SEM_TIMEDWAIT)(Semaphore *, TimeDuration);
+
+typedef struct {
+  SEM_INIT             SemInit;
+  SEM_DESTROY          SemDestroy;
+  SEM_POST             SemPost;
+  SEM_WAIT             SemWait;
+  SEM_TRYWAIT          SemTryWait;
+  SEM_TIMEDWAIT        SemTimedWait;
+
+}SemIntf;
+
+/******************************************************************************
+     Spinlock
+******************************************************************************/
+
+struct spinlock;
+typedef struct spinlock Spinlock;
+
+typedef Spinlock* (*SPINLOCK_INIT)(UINT64 Id OPTIONAL);
+typedef _Bool (*SPINLOCK_HELD)(Spinlock*);
+typedef INTN (*SPINLOCK_TRY_LOCK)(Spinlock*);
+typedef VOID (*SPINLOCK_LOCK)(Spinlock*);
+typedef VOID (*SPINLOCK_UNLOCK)(Spinlock*);
+
+typedef struct {
+  SPINLOCK_INIT          SpinLockInit;
+  SPINLOCK_HELD          SpinLockHeld;
+  SPINLOCK_TRY_LOCK      SpinTryLock;
+  SPINLOCK_LOCK          SpinLock;
+  SPINLOCK_UNLOCK        SpinUnlock;
+
+}SpinlockIntf;
+
+/******************************************************************************
+     Thread
+******************************************************************************/
+
+/* Thread priority */
+#define NUM_PRIORITIES                  32
+
+#define LOWEST_PRIORITY                 0
+#define HIGHEST_PRIORITY                (NUM_PRIORITIES - 1)
+
+#define IDLE_PRIORITY                   LOWEST_PRIORITY
+
+#define DPC_PRIORITY                    (NUM_PRIORITIES - 2)
+
+#define LOW_PRIORITY                    (NUM_PRIORITIES / 4)
+
+#define DEFAULT_PRIORITY                (NUM_PRIORITIES / 2)
+
+#define HIGH_PRIORITY                   ((NUM_PRIORITIES / 4) * 3)
+
+#define UEFI_THREAD_PRIORITY            HIGH_PRIORITY
+
+/* stack size */
+#ifdef CUSTOM_DEFAULT_STACK_SIZE
+#define DEFAULT_STACK_SIZE              CUSTOM_DEFAULT_STACK_SIZE
+#else
+#define DEFAULT_STACK_SIZE              0x1000
+#endif
+
+struct thread;
+typedef struct thread Thread;
+
+typedef INT32 (*ThreadStartRoutine) (VOID *Arg);
+
+typedef Thread* (*THREAD_CREATE)(const char *Name,
+    ThreadStartRoutine EntryPoint, VOID *Arg, INT32 Priority, UINTN Stack_size);
+typedef KStatus (*THREAD_RESUME)(Thread *);
+typedef VOID (*THREAD_EXIT)(INT32 RetCode);
+
+/* the current thread */
+typedef Thread* (*GET_CURRENT_THREAD)(VOID);
+
+typedef INT32 (*THREAD_GET_CURR_CPU)(Thread*);
+typedef INT32 (*THREAD_GET_PINNED_CPU)(Thread*);
+typedef VOID (*THREAD_SET_PINNED_CPU)(Thread*, INT32 Cpu);
+typedef VOID (*THREAD_SET_NAME)(const char *Name);
+typedef VOID (*THREAD_SET_PRIORITY)(INT32 Priority);
+
+typedef VOID (*THREAD_SLEEP)(TimeDuration Delay);
+
+typedef KStatus (*THREAD_DETACH)(Thread *);
+typedef KStatus (*THREAD_JOIN)(Thread *, INT32 *RetCode,
+    TimeDuration Timeout);
+typedef KStatus (*THREAD_DETACH_AND_RESUME)(Thread *);
+
+typedef ThreadStats* (*THREAD_GET_STATS) (Thread *, ThreadStats* Tsp);
+typedef UINT64 (*THREAD_GET_TIMESTAMP) (VOID);
+
+/* Get thread unsafe stack pointer current */
+typedef VOID** (*THREAD_GET_UNSAFE_SP_CURRENT) (Thread *);
+
+/* Get thread unsafe stack base */
+typedef VOID* (*THREAD_GET_UNSAFE_SP_BASE) (Thread *Thr);
+
+/* Returns size of padding that will be used in unsafe stack for bound check */
+typedef UINT64 (*THREAD_GET_UNSAFE_SP_PADDING_SIZE) (VOID);
+
+/* set thread unsafe stack pointer */
+/* For bound check, allocate unsafe stack of size =  required stack size +
+                                                     Padding size
+   Get Padding size by calling ThreadGetUnsafeStackPaddingSize ()
+   In Size parameter pass allocated unsafe stack size  */
+
+/* NOTE: Client should pass the memory for unsafe stack and it is the
+   responsibility of client to free up that space. */
+typedef KStatus (*THREAD_SET_THREAD_UNSAFE_SP) (Thread *,
+    ThrUnsafeStackIntf *);
+
+typedef struct {
+  THREAD_CREATE                ThreadCreate;
+  THREAD_RESUME                ThreadResume;
+  THREAD_EXIT                  ThreadExit;
+  GET_CURRENT_THREAD           GetCurrentThread;
+  THREAD_GET_CURR_CPU          ThreadGetCurrCpu;
+  THREAD_GET_PINNED_CPU        ThreadGetPinnedCpu;
+  VOID*                        Reserved3;      // Deprecated API filler
+  THREAD_SET_PINNED_CPU        ThreadSetPinnedCpu;
+  THREAD_SET_NAME              ThreadSetName;
+  THREAD_SET_PRIORITY          ThreadSetPriority;
+  THREAD_SLEEP                 ThreadSleep;
+  THREAD_DETACH                ThreadDetach;
+  THREAD_JOIN                  ThreadJoin;
+  THREAD_DETACH_AND_RESUME     ThreadDetachAndResume;
+  VOID*                        Reserved0;   // Deprecated API filler
+  VOID*                        Reserved1;   // Deprecated API filler
+  VOID*                        Reserved2;   // Deprecated API filler
+  VOID*                        Reserved4;   // Deprecated API filler
+  THREAD_GET_TIMESTAMP         ThreadGetTimeStamp;
+  THREAD_GET_STATS             ThreadGetStats;
+  THREAD_GET_UNSAFE_SP_CURRENT ThreadGetUnsafeSPCurrent;
+  THREAD_GET_UNSAFE_SP_BASE    ThreadGetUnsafeSPBase;
+  THREAD_SET_THREAD_UNSAFE_SP  ThreadSetUnsafeSP;
+  THREAD_GET_UNSAFE_SP_PADDING_SIZE ThreadGetUnsafeStackPaddingSize;
+
+}ThreadIntf;
+
+/******************************************************************************
+     Timer
+******************************************************************************/
+/* Rules for Timers:
+ * - Timer callbacks occur from interrupt context
+ * - Timers may be programmed or canceled from interrupt or thread context
+ * - Timers may be canceled or reprogrammed from within their callback
+ * - Timers currently are dispatched from a 10ms periodic tick
+*/
+
+struct timer;
+typedef struct timer Timer;
+
+typedef enum HandlerStatus (*TimerCallback) (Timer *Tmr, TimeDuration Now,
+    VOID *Arg);
+
+typedef Timer* (*TIMER_INIT)(VOID);
+typedef VOID (*TIMER_SET_ONESHOT)(Timer *, TimeDuration Delay,
+    TimerCallback Cb, VOID *arg);
+typedef VOID (*TIMER_SET_PERIODIC)(Timer *, TimeDuration Period,
+    TimerCallback Cb, VOID *arg);
+typedef VOID (*TIMER_CANCEL)(Timer *);
+
+
+typedef struct {
+  TIMER_INIT            TimerInit;
+  TIMER_SET_ONESHOT     TimerSetOneshot;
+  TIMER_SET_PERIODIC    TimerSetPeriodic;
+  TIMER_CANCEL          CancelTimer;
+
+}TimerIntf;
+
+
+/******************************************************************************
+     MP Cpu
+******************************************************************************/
+
+/*
+ *  Active CPU :
+ *  Busy CPU :
+ *  Idle CPU :
+ *
+ * */
+typedef UINT32 (*MPCORE_GET_MAX_CPU_COUNT) (VOID);
+typedef UINT32 (*MPCORE_GET_AVAIL_CPU_COUNT) (VOID);
+typedef UINT32 (*MPCORE_INIT_DEFERRED_CORES) (UINT32 Cpu_Mask);
+
+typedef UINT32 (*MPCORE_GET_CURR_CPU) (VOID);
+
+typedef UINT32 (*MPCORE_IS_CPU_ACTIVE) (UINT32 Cpu);
+
+typedef UINT32 (*MPCORE_GET_ACTIVE_MASK) (VOID);
+typedef UINT32 (*MPCORE_GET_ONLINE_MASK) (VOID);
+
+typedef VOID (*MPCORE_SHUTDOWN_SCHEDULER) (VOID);
+typedef VOID (*MPCORE_POWER_OFF_CPU) (UINT32 CpuMask);
+typedef VOID (*MPCORE_POWER_ON_CPU) (UINT32 CpuMask);
+
+typedef INT32 (*MPCORE_SLEEP_CPU) (UINT64 DurationMs);
+
+typedef CpuSchedStats* (*MPCORE_GET_CPU_SCHED_STATS) (UINT32 Cpu,
+    CpuSchedStats* Csp);
+
+/* Should be able to receive the power transition notification on any of the
+ * cores
+ * */
+typedef void (*PwrTxnNotifyFn) (enum PwrTxnType Evt, VOID* Arg);
+
+typedef EFI_STATUS (*REGISTER_PWR_TRANSITION_NOTIFY) (PwrTxnNotifyFn CbFn,
+    VOID* Arg);
+typedef EFI_STATUS (*UNREGISTER_PWR_TRANSITION_NOTIFY)
+    (PwrTxnNotifyFn CbFn);
+
+typedef struct {
+    MPCORE_GET_MAX_CPU_COUNT        MpcoreGetMaxCpuCount;
+
+    MPCORE_GET_AVAIL_CPU_COUNT      MpcoreGetAvailCpuCount;
+
+    MPCORE_INIT_DEFERRED_CORES      MpcoreInitDeferredCores;
+
+    MPCORE_GET_CURR_CPU             MpcoreGetCurrCpu;
+
+    MPCORE_IS_CPU_ACTIVE            MpcoreIsCpuActive;
+
+    MPCORE_GET_ACTIVE_MASK          MpcoreGetActiveMask;
+    MPCORE_GET_ONLINE_MASK          MpcoreGetOnlineMask;
+
+    MPCORE_SHUTDOWN_SCHEDULER       MpcoreShutdownScheduler;
+    MPCORE_POWER_OFF_CPU            MpcorePowerOffCpu;
+    MPCORE_POWER_ON_CPU             MpcorePowerOnCpu;
+
+    /* Sleep related API's
+     * NOTE: Only supported in Non retail test configuration */
+    MPCORE_SLEEP_CPU                MpcoreSleepCpu;
+
+    REGISTER_PWR_TRANSITION_NOTIFY     RegisterPwrTransitionNotify;
+    UNREGISTER_PWR_TRANSITION_NOTIFY   UnRegisterPwrTransitionNotify;
+
+    MPCORE_GET_CPU_SCHED_STATS      MpcoreGetCpuSchedStats;
+
+}MpCpuIntf;
+
+/******************************************************************************
+     Watch Dog
+******************************************************************************/
+
+typedef EFI_STATUS (*WDOG_ENABLE) (VOID);
+typedef VOID       (*WDOG_DISABLE) (VOID);
+typedef EFI_STATUS (*WDOG_SET_BITE_TIMEOUT) (UINT32 Timeoutms);
+typedef VOID       (*WDOG_FORCE_PET) (VOID);
+typedef VOID       (*WDOG_FORCE_BITE) (VOID);
+typedef EFI_STATUS (*WDOG_SET_PET_TIMER_PERIOD) (UINT32 Timeoutms);
+
+typedef struct {
+    WDOG_ENABLE               WdogEnable;
+    WDOG_DISABLE              WdogDisable;
+    WDOG_SET_BITE_TIMEOUT     WdogSetBiteTimeout;
+    WDOG_FORCE_PET            WdogForcePet;
+    WDOG_FORCE_BITE           WdogFirceBite;
+    WDOG_SET_PET_TIMER_PERIOD WdogSetPetTimerPeriod;
+}WDogIntf;
+
+
+/******************************************************************************
+      Simple and Recursible Locks
+******************************************************************************/
+struct LockType;
+typedef struct LockType LockHandle;
+
+/* Creates a lock instance. If the LockStrID has a valid string name, then
+ * the named lock is created if it already doesn't exist, if the named lock
+ * already exists, the lock created points to the same underlying instance.
+ * The Lock String name should be of length 8 chars or less, if its above 8
+ * it results into error to avoid ambiguity since underlying mutex ID len is
+ * same 8 bytes and it could be pointing to the same instance which may not
+ * be the intended
+ *
+ * The option can be provided to get the lock that is recursive (ie the same
+ * thread can lock it many times and has to unlock the same number of times) */
+typedef EFI_STATUS  (*INIT_LOCK) (IN  CONST CHAR8 *LockStrID   OPTIONAL,
+                                  OUT LockHandle** LockHandlePtr);
+
+typedef EFI_STATUS  (*INIT_RECURSIVE_LOCK)
+    (IN  CONST CHAR8 *LockStrID   OPTIONAL, OUT LockHandle** LockHandlePtr);
+
+typedef VOID        (*DESTROY_LOCK) (LockHandle*);
+typedef VOID        (*ACQUIRE_LOCK) (LockHandle*);
+typedef VOID        (*RELEASE_LOCK) (LockHandle*);
+
+typedef struct {
+    INIT_LOCK               InitLock;
+    INIT_RECURSIVE_LOCK     InitRecursiveLock;
+    DESTROY_LOCK            DestroyLock;
+    ACQUIRE_LOCK            AcquireLock;
+    RELEASE_LOCK            ReleaseLock;
+}LockIntf;
+
+/*===========================================================================
+                    PROTOCOL INTERFACE
+===========================================================================*/
+
+typedef UINT32 (*GET_LIB_VERSION) (VOID);
+
+/*
+ *  Scheduler protocol interface in UEFI. Provides the standard scheduler
+ *  services for driver/applications consumption.
+ */
+typedef struct {
+  UINT64                         Version;
+  InterruptIntf                  *Interrupt;
+  TimerIntf                      *Timer;
+  ThreadIntf                     *Thread;
+  EventIntf                      *Event;
+  MutexIntf                      *Mutex;
+  SemIntf                        *Sem;
+  SpinlockIntf                   *Spinlock;
+  MpCpuIntf                      *MpCpu;
+  WDogIntf                       *WDog;
+  GET_LIB_VERSION                 GetLibVersion; // Major [31:16], Minor {15:0]
+  LockIntf                       *Lock;
+}EFI_KERNEL_PROTOCOL;
+
+extern EFI_KERNEL_PROTOCOL* gKernel;
+
+#endif  /* ___EFI_KERNEL_PROTOCOL_H__ */
+
diff --git a/QcomModulePkg/Library/BootLib/Board.c b/QcomModulePkg/Library/BootLib/Board.c
index 7b8329a..bd23263 100644
--- a/QcomModulePkg/Library/BootLib/Board.c
+++ b/QcomModulePkg/Library/BootLib/Board.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2015-2018, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2015-2018, 2020, The Linux Foundation. All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions are
@@ -41,7 +41,9 @@
         [EMMC] = "EMMC", [UFS] = "UFS", [NAND] = "NAND", [UNKNOWN] = "Unknown",
 };
 
-EFI_STATUS
+RamPartitionEntry *RamPartitionEntries = NULL;
+
+STATIC EFI_STATUS
 GetRamPartitions (RamPartitionEntry **RamPartitions, UINT32 *NumPartitions)
 {
 
@@ -80,6 +82,32 @@
 }
 
 EFI_STATUS
+ReadRamPartitions (RamPartitionEntry **RamPartitions, UINT32 *NumPartitions)
+{
+  STATIC UINT32 NumPartitionEntries = 0;
+  EFI_STATUS Status = EFI_SUCCESS;
+
+  if (RamPartitionEntries == NULL) {
+    NumPartitionEntries = 0;
+    Status = GetRamPartitions (&RamPartitionEntries, &NumPartitionEntries);
+    if (EFI_ERROR (Status)) {
+      DEBUG ((EFI_D_ERROR, "Error returned from GetRamPartitions %r\n",
+              Status));
+      return Status;
+    }
+    if (!RamPartitionEntries) {
+      DEBUG ((EFI_D_ERROR, "RamPartitions is NULL\n"));
+      return EFI_NOT_FOUND;
+    }
+  }
+
+  *RamPartitions = RamPartitionEntries;
+  *NumPartitions = NumPartitionEntries;
+
+  return Status;
+}
+
+EFI_STATUS
 GetGranuleSize (UINT32 *MinPasrGranuleSize)
 {
   EFI_STATUS Status = EFI_NOT_FOUND;
@@ -120,15 +148,11 @@
   UINT64 SmallestBase;
   UINT32 i = 0;
 
-  Status = GetRamPartitions (&RamPartitions, &NumPartitions);
+  Status = ReadRamPartitions (&RamPartitions, &NumPartitions);
   if (EFI_ERROR (Status)) {
-    DEBUG ((EFI_D_ERROR, "Error returned from GetRamPartitions %r\n", Status));
+    DEBUG ((EFI_D_ERROR, "Error returned from ReadRamPartitions %r\n", Status));
     return Status;
   }
-  if (!RamPartitions) {
-    DEBUG ((EFI_D_ERROR, "RamPartitions is NULL\n"));
-    return EFI_NOT_FOUND;
-  }
   SmallestBase = RamPartitions[0].Base;
   for (i = 0; i < NumPartitions; i++) {
     if (SmallestBase > RamPartitions[i].Base)
@@ -136,7 +160,6 @@
   }
   *BaseMemory = SmallestBase;
   DEBUG ((EFI_D_INFO, "Memory Base Address: 0x%x\n", *BaseMemory));
-  FreePool (RamPartitions);
 
   return Status;
 }
@@ -456,6 +479,7 @@
 {
   EFI_STATUS Status;
   EFIChipInfoModemType ModemType;
+  UINT32 DdrType;
 
   Status = GetChipInfo (&platform_board_info, &ModemType);
   if (EFI_ERROR (Status))
@@ -465,6 +489,12 @@
   if (EFI_ERROR (Status))
     return Status;
 
+  Status = BoardDdrType (&DdrType);
+  if (EFI_ERROR (Status))
+    return Status;
+
+  platform_board_info.HlosSubType = (DdrType << DDR_SHIFT);
+
   if (BoardPlatformFusion ()) {
     AsciiSPrint ((CHAR8 *)platform_board_info.ChipBaseBand,
                   CHIP_BASE_BAND_LEN, "%a", CHIP_BASE_BAND_MDM);
@@ -486,6 +516,8 @@
           platform_board_info.ChipBaseBand));
   DEBUG ((EFI_D_VERBOSE, "Fusion Value    : %d\n",
           platform_board_info.PlatformInfo.fusion));
+  DEBUG ((EFI_D_VERBOSE, "HLOS SubType    : 0x%x\n",
+          platform_board_info.HlosSubType));
 
   return Status;
 }
@@ -673,3 +705,41 @@
   else
     StrHwPlatform[ChipIdValidLen - 1] = '\0';
 }
+
+EFI_STATUS BoardDdrType (UINT32 *Type)
+{
+  EFI_STATUS Status;
+  RamPartitionEntry *RamPartitions = NULL;
+  UINT32 i = 0;
+  UINT32 NumPartitions = 0;
+  UINT64 DdrSize = 0;
+
+  Status = ReadRamPartitions (&RamPartitions, &NumPartitions);
+  if (EFI_ERROR (Status)) {
+    DEBUG ((EFI_D_ERROR, "Error returned from GetRamPartitions %r\n", Status));
+    return Status;
+  }
+
+  for (i = 0; i < NumPartitions; i++) {
+    DdrSize += RamPartitions[i].AvailableLength;
+  }
+  DEBUG ((EFI_D_INFO, "Total DDR Size: 0x%016lx \n", DdrSize));
+
+  *Type = 0;
+  if (DdrSize <= DDR_256MB) {
+    *Type = DDRTYPE_256MB;
+  } else if (DdrSize <= DDR_512MB) {
+    *Type = DDRTYPE_512MB;
+  } else if (DdrSize <= DDR_1024MB) {
+    *Type = DDRTYPE_1024MB;
+  } else if (DdrSize <= DDR_2048MB) {
+    *Type = DDRTYPE_2048MB;
+  }
+
+  return Status;
+}
+
+UINT32 BoardPlatformHlosSubType (VOID)
+{
+  return platform_board_info.HlosSubType;
+}
diff --git a/QcomModulePkg/Library/BootLib/BootLib.inf b/QcomModulePkg/Library/BootLib/BootLib.inf
old mode 100644
new mode 100755
index adfeaf2..486c2fd
--- a/QcomModulePkg/Library/BootLib/BootLib.inf
+++ b/QcomModulePkg/Library/BootLib/BootLib.inf
@@ -68,6 +68,7 @@
 	LECmdLine.c
 	HypervisorMvCalls.c
 	FdtRw.c
+	ThreadStack.c
 
 [Packages]
 	ArmPkg/ArmPkg.dec
@@ -149,6 +150,7 @@
 	gQcomScmProtocolGuid
 	gEfiNandPartiGuidProtocolGuid
 	gEfiDDRGetInfoProtocolGuid
+	gEfiKernelProtocolGuid
 
 [FixedPcd]
 	gArmTokenSpaceGuid.PcdSystemMemoryBase
diff --git a/QcomModulePkg/Library/BootLib/FdtRw.c b/QcomModulePkg/Library/BootLib/FdtRw.c
index d9abea1..c5bed06 100644
--- a/QcomModulePkg/Library/BootLib/FdtRw.c
+++ b/QcomModulePkg/Library/BootLib/FdtRw.c
@@ -118,9 +118,13 @@
     Node->Next = NodeList;
     NodeList = Node;
     Node->NodeName = AllocateZeroPool (NameLen + 1);
-    CopyMem ((VOID *)Node->NodeName, NodeName, NameLen);
+    if (Node->NodeName) {
+      CopyMem ((VOID *)Node->NodeName, NodeName, NameLen);
 
-    Node->NodeOffset = NodeOffset;
+      Node->NodeOffset = NodeOffset;
+    } else {
+        FdtDeleteNodeList ();
+    }
   } else {
     FdtDeleteNodeList ();
   }
diff --git a/QcomModulePkg/Library/BootLib/LinuxLoaderLib.c b/QcomModulePkg/Library/BootLib/LinuxLoaderLib.c
index 75f9f2f..6dee2b5 100644
--- a/QcomModulePkg/Library/BootLib/LinuxLoaderLib.c
+++ b/QcomModulePkg/Library/BootLib/LinuxLoaderLib.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2015-2018, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2015-2018, 2020, The Linux Foundation. All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions are
@@ -47,6 +47,75 @@
 #define FILE_INFO_SIZE (SIZE_OF_EFI_FILE_INFO + 256)
 
 STATIC UINT32 TimerFreq, FactormS;
+
+/* Returns 0 if the volume label matches otherwise non zero */
+STATIC UINTN
+CompareVolumeLabel (IN EFI_SIMPLE_FILE_SYSTEM_PROTOCOL*   Fs,
+                    IN CHAR8*                             ReqVolumeName)
+{
+  INT32 CmpResult;
+  UINT32 j;
+  UINT16 VolumeLabel[VOLUME_LABEL_SIZE];
+  EFI_FILE_PROTOCOL  *FsVolume = NULL;
+  EFI_STATUS         Status;
+  UINTN                               Size;
+  EFI_FILE_SYSTEM_INFO                *FsInfo;
+
+  // Get information about the volume
+  Status = Fs->OpenVolume (Fs, &FsVolume);
+
+  if (Status != EFI_SUCCESS) {
+    return 1;
+  }
+
+  /* Get the Volume name */
+  Size = 0;
+  FsInfo = NULL;
+  Status = FsVolume->GetInfo (FsVolume, &gEfiFileSystemInfoGuid, &Size, FsInfo);
+  if (Status == EFI_BUFFER_TOO_SMALL) {
+    FsInfo = AllocateZeroPool (Size);
+    Status = FsVolume->GetInfo (FsVolume,
+                                &gEfiFileSystemInfoGuid, &Size, FsInfo);
+    if (Status != EFI_SUCCESS) {
+      FreePool (FsInfo);
+      return 1;
+    }
+  }
+
+  if (FsInfo == NULL) {
+    return 1;
+  }
+
+  /* Convert the passed in Volume name to Wide char and upper case */
+  for (j = 0; (j < VOLUME_LABEL_SIZE - 1) && ReqVolumeName[j]; ++j) {
+    VolumeLabel[j] = ReqVolumeName[j];
+
+    if ((VolumeLabel[j] >= 'a') &&
+        (VolumeLabel[j] <= 'z')) {
+      VolumeLabel[j] -= ('a' - 'A');
+    }
+  }
+
+  /* Null termination */
+  VolumeLabel[j] = 0;
+
+  /* Change any lower chars in volume name to upper
+   * (ideally this is not needed) */
+  for (j = 0; (j < VOLUME_LABEL_SIZE - 1) && FsInfo->VolumeLabel[j]; ++j) {
+    if ((FsInfo->VolumeLabel[j] >= 'a') &&
+          (FsInfo->VolumeLabel[j] <= 'z')) {
+      FsInfo->VolumeLabel[j] -= ('a' - 'A');
+    }
+  }
+
+  CmpResult = StrnCmp (FsInfo->VolumeLabel, VolumeLabel, VOLUME_LABEL_SIZE);
+
+  FreePool (FsInfo);
+  FsVolume->Close (FsVolume);
+
+  return CmpResult;
+}
+
 /**
   Returns a list of BlkIo handles based on required criteria
 SelectionAttrib : Bitmask representing the conditions that need
@@ -67,7 +136,7 @@
 GetBlkIOHandles (IN UINT32 SelectionAttrib,
                  IN PartiSelectFilter *FilterData,
                  OUT HandleInfo *HandleInfoPtr,
-                 IN OUT UINT32 *MaxBlkIopCnt)
+                 IN OUT UINT32* MaxBlkIopCnt)
 {
   EFI_BLOCK_IO_PROTOCOL *BlkIo;
   EFI_HANDLE *BlkIoHandles;
@@ -79,6 +148,7 @@
   EFI_DEVICE_PATH_PROTOCOL *DevPathInst;
   EFI_DEVICE_PATH_PROTOCOL *TempDevicePath;
   VENDOR_DEVICE_PATH *RootDevicePath;
+  EFI_SIMPLE_FILE_SYSTEM_PROTOCOL     *Fs;
   UINT32 BlkIoCnt = 0;
   EFI_PARTITION_ENTRY *PartEntry;
 
@@ -119,6 +189,10 @@
 
     Status = gBS->HandleProtocol (BlkIoHandles[i], &gEfiBlockIoProtocolGuid,
                                   (VOID **)&BlkIo);
+    /* Fv volumes will not support Blk I/O protocol */
+    if (Status == EFI_UNSUPPORTED) {
+      continue;
+    }
 
     if (Status != EFI_SUCCESS) {
       DEBUG ((EFI_D_ERROR, "Unable to get Filesystem Handle %r\n", Status));
@@ -156,12 +230,9 @@
 
       if ((SelectionAttrib & (BLK_IO_SEL_SELECT_ROOT_DEVICE_ONLY |
                               BLK_IO_SEL_MATCH_ROOT_DEVICE)) != 0) {
-        if (!FilterData || (FilterData->RootDeviceType == NULL)) {
-          FreePool (BlkIoHandles);
-          BlkIoHandles = NULL;
+        if (!FilterData) {
           return EFI_INVALID_PARAMETER;
         }
-
         /* If this is not the root device that we are looking for, ignore this
          * handle */
         if (RootDevicePath->Header.Type != HARDWARE_DEVICE_PATH ||
@@ -169,8 +240,9 @@
             (RootDevicePath->Header.Length[0] |
              (RootDevicePath->Header.Length[1] << 8)) !=
                 sizeof (VENDOR_DEVICE_PATH) ||
-            CompareGuid (FilterData->RootDeviceType, &RootDevicePath->Guid) ==
-                FALSE)
+            ((FilterData->RootDeviceType != NULL) &&
+             (CompareGuid (FilterData->RootDeviceType,
+                           &RootDevicePath->Guid) == FALSE)))
           continue;
       }
 
@@ -206,26 +278,55 @@
         /* PartitionDxe implementation should return partition type also */
         if ((SelectionAttrib & BLK_IO_SEL_MATCH_PARTITION_TYPE_GUID) != 0) {
           GUID *PartiType;
-          if (!FilterData || (FilterData->PartitionType == NULL)) {
-            FreePool (BlkIoHandles);
-            BlkIoHandles = NULL;
+          VOID *Interface;
+
+          if (!FilterData ||
+                FilterData->PartitionType == NULL) {
             return EFI_INVALID_PARAMETER;
           }
 
-          Status = gBS->HandleProtocol (BlkIoHandles[i], &gEfiPartitionTypeGuid,
-                                        (VOID **)&PartiType);
-          if (Status != EFI_SUCCESS)
-            continue;
+          Status = gBS->HandleProtocol (BlkIoHandles[i],
+                                        FilterData->PartitionType,
+                                        (VOID**)&Interface);
+          if (EFI_ERROR (Status)) {
+              Status = gBS->HandleProtocol (BlkIoHandles[i],
+                              &gEfiPartitionTypeGuid,
+                              (VOID **)&PartiType);
+              if (EFI_ERROR (Status)) {
+                continue;
+              }
 
-          if (CompareGuid (PartiType, FilterData->PartitionType) == FALSE)
-            continue;
+              if (CompareGuid (PartiType, FilterData->PartitionType) == FALSE) {
+                continue;
+              }
+          }
         }
       }
       /* If we wanted a particular partition and didn't get the HDD DP,
          then this handle is probably not the interested ones */
       else if ((SelectionAttrib & BLK_IO_SEL_MATCH_PARTITION_TYPE_GUID) != 0)
-        continue;
+          continue;
     }
+
+    /* Check if the Filesystem related criteria satisfies */
+    if ((SelectionAttrib & BLK_IO_SEL_SELECT_MOUNTED_FILESYSTEM) != 0) {
+      Status = gBS->HandleProtocol (BlkIoHandles[i],
+                               &gEfiSimpleFileSystemProtocolGuid, (VOID **)&Fs);
+      if (EFI_ERROR (Status)) {
+        continue;
+      }
+
+      if ((SelectionAttrib & BLK_IO_SEL_SELECT_BY_VOLUME_NAME) != 0) {
+        if (!FilterData ||
+             FilterData->VolumeName == NULL) {
+          return EFI_INVALID_PARAMETER;
+        }
+        if (CompareVolumeLabel (Fs, FilterData->VolumeName) != 0) {
+          continue;
+        }
+      }
+    }
+
     /* Check if the Partition name related criteria satisfies */
     if ((SelectionAttrib & BLK_IO_SEL_MATCH_PARTITION_LABEL) != 0) {
       Status = gBS->HandleProtocol (BlkIoHandles[i], &gEfiPartitionRecordGuid,
@@ -547,7 +648,8 @@
        side timeout. So split the image into small writing units  to let usb
        have chance to champ in and doing work in parallel.
       */
-    if (!IsUsbTimerStarted ()) {
+
+    if (!IsFlashSplitNeeded ()) {
       WriteUnitSize = DivMsgBufSize;
     }
 
diff --git a/QcomModulePkg/Library/BootLib/LocateDeviceTree.c b/QcomModulePkg/Library/BootLib/LocateDeviceTree.c
index 9b65901..4c0e5cd 100644
--- a/QcomModulePkg/Library/BootLib/LocateDeviceTree.c
+++ b/QcomModulePkg/Library/BootLib/LocateDeviceTree.c
@@ -742,9 +742,10 @@
 
     DEBUG ((EFI_D_VERBOSE, "BoardSubtype = %x, DtSubType = %x\n",
             BoardPlatformSubType (), CurDtbInfo->DtPlatformSubtype));
-    if (CurDtbInfo->DtPlatformSubtype == BoardPlatformSubType ()) {
+    if ((CurDtbInfo->DtPlatformSubtype & PLATFORM_SUBTYPE_MASK) ==
+        BoardPlatformSubType ()) {
       CurDtbInfo->DtMatchVal |= BIT (SUBTYPE_EXACT_MATCH);
-    } else if (CurDtbInfo->DtPlatformSubtype == 0) {
+    } else if ((CurDtbInfo->DtPlatformSubtype & PLATFORM_SUBTYPE_MASK) == 0) {
       CurDtbInfo->DtMatchVal |= BIT (SUBTYPE_DEFAULT_MATCH);
     } else {
       DEBUG ((EFI_D_VERBOSE, "subtype-id doesnot match\n"));
@@ -752,6 +753,13 @@
       CurDtbInfo->DtMatchVal = BIT (NONE_MATCH);
       return EFI_NOT_FOUND;
     }
+
+    if ((CurDtbInfo->DtPlatformSubtype & DDR_MASK) ==
+        (BoardPlatformHlosSubType() & DDR_MASK)) {
+      CurDtbInfo->DtMatchVal |= BIT (DDR_MATCH);
+    } else {
+      DEBUG ((EFI_D_VERBOSE, "ddr size does not match\n"));
+    }
   } else {
     DEBUG ((EFI_D_VERBOSE, "qcom,board-id does not exist (or) (%d) "
                            "is not a multiple of (%d)\n",
@@ -1199,6 +1207,7 @@
 platform_dt_absolute_match (struct dt_entry *cur_dt_entry,
                             struct dt_entry_node *dt_list)
 {
+  UINT32 cur_dt_hlos_ddr;
   UINT32 cur_dt_hw_platform;
   UINT32 cur_dt_hw_subtype;
   UINT32 cur_dt_msm_id;
@@ -1212,6 +1221,9 @@
   cur_dt_hw_platform = (cur_dt_entry->variant_id & 0x000000ff);
   cur_dt_hw_subtype = (cur_dt_entry->board_hw_subtype & 0xff);
 
+  /* Bits 10:8 contain ddr information */
+  cur_dt_hlos_ddr = (cur_dt_entry->board_hw_subtype & 0x700);
+
   /* 1. must match the msm_id, platform_hw_id, platform_subtype and DDR size
    *  soc, board major/minor, pmic major/minor must less than board info
    *  2. find the matched DTB then return 1
@@ -1221,6 +1233,7 @@
   if ((cur_dt_msm_id == (BoardPlatformRawChipId () & 0x0000ffff)) &&
       (cur_dt_hw_platform == BoardPlatformType ()) &&
       (cur_dt_hw_subtype == BoardPlatformSubType ()) &&
+      (cur_dt_hlos_ddr == (BoardPlatformHlosSubType() & 0x700)) &&
       (cur_dt_entry->soc_rev <= BoardPlatformChipVersion ()) &&
       ((cur_dt_entry->variant_id & 0x00ffff00) <=
        (BoardTargetId () & 0x00ffff00)) &&
@@ -1287,6 +1300,10 @@
       current_info = ((dt_node_tmp1->dt_entry_m->platform_id) & 0x00ff0000);
       board_info = BoardPlatformFoundryId () << 16;
       break;
+    case DTB_DDR:
+      current_info = ((dt_node_tmp1->dt_entry_m->board_hw_subtype) & 0x700);
+      board_info = (BoardPlatformHlosSubType () & 0x700);
+      break;
     case DTB_PMIC_MODEL:
       for (i = 0; i < 4; i++) {
         current_pmic_model[i] = (dt_node_tmp1->dt_entry_m->pmic_rev[i] & 0xff);
@@ -1328,6 +1345,9 @@
     case DTB_FOUNDRY:
       current_info = ((dt_node_tmp1->dt_entry_m->platform_id) & 0x00ff0000);
       break;
+    case DTB_DDR:
+      current_info = ((dt_node_tmp1->dt_entry_m->board_hw_subtype) & 0x700);
+      break;
     case DTB_PMIC_MODEL:
       for (i = 0; i < 4; i++) {
         current_pmic_model[i] = (dt_node_tmp1->dt_entry_m->pmic_rev[i] & 0xff);
@@ -1515,6 +1535,12 @@
   */
   platform_dt_absolute_compat_match (dt_list, DTB_FOUNDRY);
 
+  /* check DDR type
+  * the DDR type must exact match board DDR tpe, this is compatibility
+  * check, if couldn't find the exact match from DTB, will exact match 0x0.
+  */
+  platform_dt_absolute_compat_match (dt_list, DTB_DDR);
+
   /* check PMIC model
   * the PMIC model must exact match board PMIC model, this is compatibility
   * check, if couldn't find the exact match from DTB, will exact match 0x0.
diff --git a/QcomModulePkg/Library/BootLib/Rtic.c b/QcomModulePkg/Library/BootLib/Rtic.c
index b928bed..62e943e 100644
--- a/QcomModulePkg/Library/BootLib/Rtic.c
+++ b/QcomModulePkg/Library/BootLib/Rtic.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2017-2018, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2017-2018, 2020, The Linux Foundation. All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions are
@@ -80,7 +80,6 @@
 BOOLEAN
 GetRticDtb (VOID *Dtb)
 {
-  EFI_STATUS Status = EFI_SUCCESS;
   int RootOffset;
   const char *RticProp = NULL;
   const char *MpDataProp = NULL;
@@ -90,7 +89,6 @@
   UINT8 *MpData = NULL;
   UINT32 i;
   UINT64 *MpDataAddr;
-  UINT64 BaseMemory = 0;
 
   RootOffset = fdt_path_offset (Dtb, "/");
   if (RootOffset < 0)
@@ -133,13 +131,6 @@
   }
 
   MpDataAddr = (UINT64 *)MpData;
-  Status = BaseMem (&BaseMemory);
-  if (Status != EFI_SUCCESS) {
-    DEBUG ((EFI_D_ERROR, "Base memory not found!!! Status:%r\n", Status));
-    FreePool (MpData);
-    MpData = NULL;
-    return FALSE;
-  }
 
   /* Display the RTIC id and mpdata */
   DEBUG ((EFI_D_VERBOSE, "rtic-id (%x)\n", RticData.Id));
diff --git a/QcomModulePkg/Library/BootLib/ShutdownServices.c b/QcomModulePkg/Library/BootLib/ShutdownServices.c
old mode 100644
new mode 100755
index f863226..d9c6e50
--- a/QcomModulePkg/Library/BootLib/ShutdownServices.c
+++ b/QcomModulePkg/Library/BootLib/ShutdownServices.c
@@ -17,6 +17,7 @@
 
 #include "ShutdownServices.h"
 
+#include <FastbootLib/FastbootCmds.h>
 #include <Guid/ArmMpCoreInfo.h>
 #include <Guid/FileInfo.h>
 #include <Guid/GlobalVariable.h>
@@ -40,6 +41,8 @@
   UINT32 DescriptorVersion;
   UINTN Pages;
 
+  WaitForFlashFinished ();
+
   MemoryMap = NULL;
   MemoryMapSize = 0;
   Pages = 0;
@@ -102,6 +105,8 @@
   ResetDataType ResetData;
   EFI_STATUS Status = EFI_INVALID_PARAMETER;
 
+  WaitForFlashFinished ();
+
   StrnCpyS (ResetData.DataBuffer, ARRAY_SIZE (ResetData.DataBuffer),
             (CONST CHAR16 *)STR_RESET_PARAM, ARRAY_SIZE (STR_RESET_PARAM) - 1);
   ResetData.Bdata = RebootReason;
@@ -120,6 +125,9 @@
 VOID ShutdownDevice (VOID)
 {
   EFI_STATUS Status = EFI_INVALID_PARAMETER;
+
+  WaitForFlashFinished ();
+
   gRT->ResetSystem (EfiResetShutdown, Status, 0, NULL);
 
   /* Flow never comes here and is fatal if it comes here.*/
diff --git a/QcomModulePkg/Library/BootLib/ThreadStack.c b/QcomModulePkg/Library/BootLib/ThreadStack.c
new file mode 100755
index 0000000..77050b0
--- /dev/null
+++ b/QcomModulePkg/Library/BootLib/ThreadStack.c
@@ -0,0 +1,347 @@
+/* Copyright (c) 2020, The Linux Foundation. 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 Linux Foundation 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 "BootLinux.h"
+#include "Library/ThreadStack.h"
+#include <Library/DebugLib.h>
+#include "LinuxLoaderLib.h"
+
+STATIC EFI_KERNEL_PROTOCOL  *KernIntf = NULL;
+STATIC VOID* UnSafeStackPtr;
+STATIC BOOLEAN IsMultiStack = TRUE;
+// This is a runtime variable to record if "thread unsafe stack low level" is
+// supported,  if TRUE, we can set/get multithread stack by API, if FALSE, we
+// can manage stack by link table.
+STATIC BOOLEAN IsThreadUSSLLSupported = FALSE;
+STATIC THREAD_STACK_NODE * ThreadStackNodeList;
+
+STATIC THREAD_STACK_NODE * ThreadStackNodeInit (Thread *thread)
+{
+  THREAD_STACK_NODE *ThreadStackNodeTmp =
+          AllocateZeroPool (sizeof (THREAD_STACK_NODE));
+
+  if (ThreadStackNodeTmp == NULL) {
+    DEBUG ((EFI_D_ERROR, "Failed to Allocate memory for "
+            "ThreadStackNodeTmp\n"));
+    return NULL;
+  }
+
+  list_clear_node (&ThreadStackNodeTmp->Node);
+
+  ThreadStackNodeTmp->ThreadStackEntry =
+          AllocateZeroPool (sizeof (THREAD_STACK_ENTRY));
+
+  if (!ThreadStackNodeTmp->ThreadStackEntry) {
+    DEBUG ((EFI_D_ERROR, "Failed to Allocate memory for "
+            "ThreadStackNodeTmp->ThreadStackEntry\n"));
+    FreePool (ThreadStackNodeTmp);
+    ThreadStackNodeTmp = NULL;
+    return NULL;
+  }
+
+  ThreadStackNodeTmp->ThreadStackEntry->Thread = thread;
+
+  ThreadStackNodeTmp->ThreadStackEntry->StackBottom =
+          AllocateZeroPool (BOOT_LOADER_MAX_UNSAFE_STACK_SIZE);
+
+  if (!ThreadStackNodeTmp->ThreadStackEntry->StackBottom) {
+    DEBUG ((EFI_D_ERROR, "Failed to Allocate memory for "
+            "ThreadStackNodeTmp->ThreadStackEntry->StackBottom \n"));
+    FreePool (ThreadStackNodeTmp->ThreadStackEntry);
+    FreePool (ThreadStackNodeTmp);
+    ThreadStackNodeTmp->ThreadStackEntry = NULL;
+    ThreadStackNodeTmp = NULL;
+    return NULL;
+  }
+
+  ThreadStackNodeTmp->ThreadStackEntry->StackTop =
+          ThreadStackNodeTmp->ThreadStackEntry->StackBottom;
+  ThreadStackNodeTmp->ThreadStackEntry->StackTop
+          += BOOT_LOADER_MAX_UNSAFE_STACK_SIZE;
+
+  return ThreadStackNodeTmp;
+}
+
+/* If kernel version is bigger than EFI_KERNEL_PROTOCOL_VER_UNSAFE_STACK_APIS,
+ * use API to set/get stack, or else use link table
+**/
+STATIC EFI_STATUS ThreadStackListCreate (VOID)
+{
+  ThreadStackNodeList = AllocateZeroPool (sizeof (THREAD_STACK_NODE));
+  if (!ThreadStackNodeList) {
+    DEBUG ((EFI_D_ERROR, "Failed to Allocate memory for stack list \n"));
+    return EFI_OUT_OF_RESOURCES;
+  }
+
+  list_initialize (&ThreadStackNodeList->Node);
+  //No entry for head
+  ThreadStackNodeList->ThreadStackEntry = NULL;
+  return EFI_SUCCESS;
+}
+
+STATIC THREAD_STACK_NODE *GetStackTableByThread (Thread *CurrentThread)
+{
+  THREAD_STACK_NODE *ThreadStackNodeTmp = NULL, *ThreadStackNode = NULL;
+
+  if (ThreadStackNodeList == NULL) {
+    DEBUG ((EFI_D_ERROR, "getStackTableByThread ThreadStackNode not"
+        "created\n"));
+    return NULL;
+  }
+
+  if (CurrentThread == NULL) {
+    DEBUG ((EFI_D_ERROR, "getStackTableByThread CurrentThread is NULL \n"));
+    return NULL;
+  }
+
+  list_for_every_entry_safe (&(ThreadStackNodeList->Node), ThreadStackNode,
+          ThreadStackNodeTmp, THREAD_STACK_NODE, Node) {
+    if (ThreadStackNode->ThreadStackEntry &&
+        (ThreadStackNode->ThreadStackEntry->Thread == CurrentThread)) {
+      return ThreadStackNode;
+    }
+  }
+
+  return NULL;
+}
+
+VOID ThreadStackNodeRemove (Thread *CurrentThread)
+{
+  THREAD_STACK_NODE *ThreadStackNodeTmp = NULL;
+
+  if (IsThreadUSSLLSupported) {
+    return;
+  }
+
+  if (CurrentThread == NULL) {
+    DEBUG ((EFI_D_VERBOSE, "Remove NULL thread pointer, drop it\n"));
+    return ;
+  }
+
+  ThreadStackNodeTmp = GetStackTableByThread (CurrentThread);
+  if (!ThreadStackNodeTmp) {
+    DEBUG ((EFI_D_VERBOSE, "try to remove a NULL node"));
+    return ;
+  }
+
+  //Remove and clean current thread stack
+  list_delete (&ThreadStackNodeTmp->Node);
+  FreePool (ThreadStackNodeTmp->ThreadStackEntry->StackBottom);
+  ThreadStackNodeTmp->ThreadStackEntry->StackBottom = NULL;
+  ThreadStackNodeTmp->ThreadStackEntry->StackTop = NULL;
+  ThreadStackNodeTmp->ThreadStackEntry->Thread = NULL;
+  FreePool (ThreadStackNodeTmp->ThreadStackEntry);
+  ThreadStackNodeTmp->ThreadStackEntry = NULL;
+  FreePool (ThreadStackNodeTmp);
+  ThreadStackNodeTmp = NULL;
+
+  DEBUG ((EFI_D_VERBOSE, " remove CurrentThread = %r stack\n", CurrentThread));
+
+  return;
+}
+
+STATIC EFI_STATUS __attribute__ ( (no_sanitize ("safe-stack")))
+AllocateGlobalUnSafeStackPtr (VOID)
+{
+  EFI_STATUS Status = EFI_SUCCESS;
+
+  UnSafeStackPtr = AllocateZeroPool (BOOT_LOADER_MAX_UNSAFE_STACK_SIZE);
+  if (UnSafeStackPtr == NULL) {
+    DEBUG ((EFI_D_ERROR, "Failed to Allocate memory for UnSafeStack \n"));
+    Status = EFI_OUT_OF_RESOURCES;
+    return Status;
+  }
+
+  UnSafeStackPtr += BOOT_LOADER_MAX_UNSAFE_STACK_SIZE;
+
+  return Status;
+}
+
+/* Add stack and thread in list, then we can get stack by thread.
+ */
+EFI_STATUS __attribute__ ( (no_sanitize ("safe-stack")))
+AllocateUnSafeStackPtr (Thread *CurrentThread)
+{
+  EFI_STATUS Status = EFI_SUCCESS;
+  THREAD_STACK_NODE *ThreadStackNodeTmp = NULL;
+  VOID* UnSafeStackPtr = NULL;
+  ThrUnsafeStackIntf ThrUnsafeStackIntf = {
+      NULL,
+      BOOT_LOADER_MAX_UNSAFE_STACK_SIZE,
+      ThreadStackReleaseCb,
+      CurrentThread,
+    };
+
+  if (CurrentThread == NULL) {
+    DEBUG ((EFI_D_ERROR, "Add NULL thread pointer, drop it\n"));
+    return EFI_INVALID_PARAMETER;
+  }
+
+  if (IsThreadUSSLLSupported) {
+    UnSafeStackPtr = AllocatePages (ALIGN_PAGES (
+        BOOT_LOADER_MAX_UNSAFE_STACK_SIZE, ALIGNMENT_MASK_4KB));
+    if (UnSafeStackPtr == NULL) {
+      DEBUG ((EFI_D_ERROR, "Failed to Allocate memory for UnSafeStack \n"));
+      Status = EFI_OUT_OF_RESOURCES;
+      return Status;
+    }
+
+    DEBUG ((EFI_D_VERBOSE, "AllocateUnSafeStackPtr CurrentThread = 0x%x,"
+        "UnSafeStackPtr = 0x%x with API \n", CurrentThread, UnSafeStackPtr));
+
+    ThrUnsafeStackIntf.unsafe_sp_base = UnSafeStackPtr;
+
+    Status = KernIntf->Thread->ThreadSetUnsafeSP (CurrentThread,
+        &ThrUnsafeStackIntf);
+
+    if (Status != EFI_SUCCESS) {
+      DEBUG ((EFI_D_ERROR, "AllocateUnSafeStackPtr ThreadSetThreadUnsafeSP"
+          "failed, Status = %d \n", Status));
+    }
+
+    return Status;
+  }
+
+  //Thread unsafe stack low level is not supported, set stack by link table
+  DEBUG ((EFI_D_VERBOSE, "AllocateUnSafeStackPtr CurrentThread = 0x%x with link"
+      "table \n", CurrentThread));
+  if (ThreadStackNodeList == NULL) {
+    DEBUG ((EFI_D_ERROR, "ThreadStackNodeAppend ThreadStackNode not"
+        "created.\n"));
+    return EFI_INVALID_PARAMETER;
+  }
+  ThreadStackNodeTmp = ThreadStackNodeInit (CurrentThread);
+  if (!ThreadStackNodeTmp) {
+    return EFI_OUT_OF_RESOURCES;
+  }
+
+  list_add_tail (&ThreadStackNodeList->Node, &ThreadStackNodeTmp->Node);
+
+  return EFI_SUCCESS;
+}
+
+//This function is to return the Unsafestack ptr address
+VOID** __attribute__ ( (no_sanitize ("safe-stack")))
+__safestack_pointer_address (VOID)
+{
+  THREAD_STACK_NODE *ThreadStackNodeTmp = NULL;
+
+  if (!IsMultiStack) {
+      return (VOID**) &UnSafeStackPtr;
+  }
+
+  if (KernIntf == NULL) {
+    return NULL;
+  }
+
+  if (IsThreadUSSLLSupported) {
+    return KernIntf->Thread->ThreadGetUnsafeSPCurrent (
+        KernIntf->Thread->GetCurrentThread ());
+  }
+
+  //Thread unsafe stack low level is not supported, get stack by link table
+  ThreadStackNodeTmp =
+      GetStackTableByThread (KernIntf->Thread->GetCurrentThread ());
+  if (!ThreadStackNodeTmp ||
+      !ThreadStackNodeTmp->ThreadStackEntry) {
+    return (VOID**) &UnSafeStackPtr;
+  }
+
+  return (VOID**) &(ThreadStackNodeTmp->ThreadStackEntry->StackTop);
+}
+
+/**
+  If IsThreadUSSLLSupported is true, UEFI core will call back here to free
+  stack, if false, UEFI client link table use ThreadStackNodeRemove () to free
+  stack.
+ **/
+VOID ThreadStackReleaseCb (VOID * Arg)
+{
+  VOID* UnSafeStackPtr = NULL;
+  Thread *CurrentThread =  (Thread *)Arg;
+  if (IsThreadUSSLLSupported) {
+    UnSafeStackPtr = KernIntf->Thread->ThreadGetUnsafeSPBase (CurrentThread);
+    DEBUG ((EFI_D_VERBOSE, "ThreadStackReleaseCb UnSafeStackPtr = 0x%x\n",
+        UnSafeStackPtr));
+
+    FreePages (UnSafeStackPtr, ALIGN_PAGES (
+        BOOT_LOADER_MAX_UNSAFE_STACK_SIZE, ALIGNMENT_MASK_4KB));
+
+    UnSafeStackPtr = NULL;
+  }
+}
+
+/* 1. if EFI Kernel Protocol is not supported in UEFI core, allocate global
+      stack for main and timer;
+   2. If supported, but kernel version is smaller than
+      EFI_KERNEL_PROTOCOL_VER_UNSAFE_STACK_APIS, alloctate by link table;
+   3. If equal to or bigger, nothing need to to in ABL, UEFI core will manage
+      main and timer thread stack;
+ */
+EFI_STATUS InitThreadUnsafeStack (VOID)
+{
+  EFI_STATUS Status = EFI_SUCCESS;
+
+  Status = gBS->LocateProtocol (&gEfiKernelProtocolGuid, NULL,
+        (VOID **)&KernIntf);
+
+  if ((Status != EFI_SUCCESS) ||
+      (KernIntf == NULL) ||
+      KernIntf->Version < EFI_KERNEL_PROTOCOL_VER_THR_CPU_STATS) {
+    DEBUG ((EFI_D_VERBOSE, "multi stack is not supported, using global"
+          " single stack.\n"));
+
+    IsMultiStack = FALSE;
+    return AllocateGlobalUnSafeStackPtr ();
+  }
+
+  DEBUG ((EFI_D_VERBOSE, "SetThreadStackEnv () kernel version = 0x%x \n",
+      KernIntf->Version));
+  if (KernIntf->Version >= EFI_KERNEL_PROTOCOL_VER_UNSAFE_STACK_APIS) {
+    IsThreadUSSLLSupported = TRUE;
+  }
+
+  if (!IsThreadUSSLLSupported) {
+    //Allocate gloabl anyway, if some thread get null stack, return gloabal
+    AllocateGlobalUnSafeStackPtr ();
+
+    Status =  ThreadStackListCreate ();
+    if (Status != EFI_SUCCESS) {
+      DEBUG ((EFI_D_VERBOSE, "Unable to Init thread unsafe stack: %r.\n",
+              Status));
+      return Status;
+    }
+
+    Status = AllocateUnSafeStackPtr (KernIntf->Thread->GetCurrentThread ());
+    if (Status != EFI_SUCCESS) {
+      DEBUG ((EFI_D_ERROR, "Unable to Allocate memory for Unsafe Stack: %r\n",
+                Status));
+      return Status;
+    }
+  }
+  return Status;
+}
diff --git a/QcomModulePkg/Library/BootLib/UpdateDeviceTree.c b/QcomModulePkg/Library/BootLib/UpdateDeviceTree.c
index cfd6400..80dd9f8 100644
--- a/QcomModulePkg/Library/BootLib/UpdateDeviceTree.c
+++ b/QcomModulePkg/Library/BootLib/UpdateDeviceTree.c
@@ -71,6 +71,24 @@
 }
 
 STATIC EFI_STATUS
+ValidateDdrRankChannel (struct ddr_details_entry_info *DdrInfo)
+{
+  if (DdrInfo->num_channels > MAX_CHANNELS) {
+    DEBUG ((EFI_D_ERROR, "ERROR: Number of channels is over the limit\n"));
+    return EFI_INVALID_PARAMETER;
+  }
+
+  for (UINT8 Chan = 0; Chan < DdrInfo->num_channels; Chan++) {
+    if (DdrInfo->num_ranks[Chan] > MAX_RANKS) {
+      DEBUG ((EFI_D_ERROR, "ERROR: Number of ranks is over the limit\n"));
+      return EFI_INVALID_PARAMETER;
+    }
+  }
+
+  return EFI_SUCCESS;
+}
+
+STATIC EFI_STATUS
 GetDDRInfo (struct ddr_details_entry_info *DdrInfo,
             UINT64 *Revision)
 {
@@ -91,6 +109,7 @@
     DEBUG ((EFI_D_ERROR, "INFO: GetDDR details failed\n"));
     return Status;
   }
+
   *Revision = DdrInfoIf->Revision;
   DEBUG ((EFI_D_VERBOSE, "DDR Header Revision =0x%x\n", *Revision));
   return Status;
@@ -347,15 +366,11 @@
     return Status;
   }
 
-  Status = GetRamPartitions (&RamPartitions, &NumPartitions);
+  Status = ReadRamPartitions (&RamPartitions, &NumPartitions);
   if (EFI_ERROR (Status)) {
-    DEBUG ((EFI_D_ERROR, "Error returned from GetRamPartitions %r\n", Status));
+    DEBUG ((EFI_D_ERROR, "Error returned from ReadRamPartitions %r\n", Status));
     return Status;
   }
-  if (!RamPartitions) {
-    DEBUG ((EFI_D_ERROR, "RamPartitions is NULL\n"));
-    return EFI_NOT_FOUND;
-  }
 
   DEBUG ((EFI_D_INFO, "RAM Partitions\r\n"));
   for (i = 0; i < NumPartitions; i++) {
@@ -379,6 +394,7 @@
 
   FreePool (RamPartitions);
   RamPartitions = NULL;
+  RamPartitionEntries = NULL;
 
   return EFI_SUCCESS;
 }
@@ -550,6 +566,11 @@
               "ddr_device_rank, HBB not supported in Revision=0x%x\n",
               Revision));
     } else {
+      Status = ValidateDdrRankChannel (DdrInfo);
+      if (Status != EFI_SUCCESS) {
+        goto OutofUpdateRankChannel;
+      }
+
       DEBUG ((EFI_D_VERBOSE, "DdrInfo->num_channels:%d\n",
               DdrInfo->num_channels));
       for (UINT8 Chan = 0; Chan < DdrInfo->num_channels; Chan++) {
@@ -590,6 +611,8 @@
     }
   }
 
+OutofUpdateRankChannel:
+
   UpdateSplashMemInfo (fdt);
 
   /* Get offset of the chosen node */
diff --git a/QcomModulePkg/Library/FastbootLib/FastbootCmds.c b/QcomModulePkg/Library/FastbootLib/FastbootCmds.c
old mode 100644
new mode 100755
index 6849d6d..94d0228
--- a/QcomModulePkg/Library/FastbootLib/FastbootCmds.c
+++ b/QcomModulePkg/Library/FastbootLib/FastbootCmds.c
@@ -56,6 +56,7 @@
 #include <Library/PartitionTableUpdate.h>
 #include <Library/PcdLib.h>
 #include <Library/PrintLib.h>
+#include <Library/ThreadStack.h>
 #include <Library/UefiApplicationEntryPoint.h>
 #include <Library/UefiBootServicesTableLib.h>
 #include <Library/UefiLib.h>
@@ -170,7 +171,12 @@
 STATIC UINT8 *mFlashDataBuffer = NULL;
 STATIC UINT8 *mUsbDataBuffer = NULL;
 
+STATIC EFI_KERNEL_PROTOCOL  *KernIntf = NULL;
+STATIC BOOLEAN IsMultiThreadSupported = FALSE;
 STATIC BOOLEAN IsFlashComplete = TRUE;
+STATIC LockHandle *LockDownload;
+STATIC LockHandle *LockFlash;
+
 STATIC EFI_STATUS FlashResult = EFI_SUCCESS;
 #ifdef ENABLE_UPDATE_PARTITIONS_CMDS
 STATIC EFI_EVENT UsbTimerEvent;
@@ -204,13 +210,34 @@
   VOID *Data;
 } CmdInfo;
 
+typedef struct {
+  CHAR16 PartitionName[MAX_GPT_NAME_SIZE];
+  UINT32 PartitionSize;
+  UINT8 *FlashDataBuffer;
+  UINT64 FlashNumDataBytes;
+} FlashInfo;
+
+STATIC BOOLEAN FlashSplitNeeded;
 STATIC BOOLEAN UsbTimerStarted;
 
-BOOLEAN IsUsbTimerStarted (VOID)
-{
+BOOLEAN IsUsbTimerStarted (VOID) {
   return UsbTimerStarted;
 }
 
+BOOLEAN IsFlashSplitNeeded (VOID)
+{
+  if (IsUseMThreadParallel ()) {
+    return FlashSplitNeeded;
+  } else {
+    return UsbTimerStarted;
+  }
+}
+
+BOOLEAN FlashComplete (VOID)
+{
+  return IsFlashComplete;
+}
+
 #ifdef DISABLE_PARALLEL_DOWNLOAD_FLASH
 BOOLEAN IsDisableParallelDownloadFlash (VOID)
 {
@@ -1290,6 +1317,59 @@
 
   return Status;
 }
+
+INT32 __attribute__ ( (no_sanitize ("safe-stack")))
+SparseImgFlashThread (VOID* Arg)
+{
+  Thread* CurrentThread = KernIntf->Thread->GetCurrentThread ();
+  FlashInfo* ThreadFlashInfo = (FlashInfo*) Arg;
+
+  if (!ThreadFlashInfo || !ThreadFlashInfo->FlashDataBuffer) {
+    return 0;
+  }
+
+  KernIntf->Lock->AcquireLock (LockFlash);
+  IsFlashComplete = FALSE;
+  FlashSplitNeeded = TRUE;
+
+  HandleSparseImgFlash (ThreadFlashInfo->PartitionName,
+          ThreadFlashInfo->PartitionSize,
+          ThreadFlashInfo->FlashDataBuffer,
+          ThreadFlashInfo->FlashNumDataBytes);
+
+  FlashSplitNeeded = FALSE;
+  IsFlashComplete = TRUE;
+  KernIntf->Lock->ReleaseLock (LockFlash);
+
+  ThreadStackNodeRemove (CurrentThread);
+
+  FreePool (ThreadFlashInfo);
+  ThreadFlashInfo = NULL;
+
+  KernIntf->Thread->ThreadExit (0);
+
+  return 0;
+}
+
+EFI_STATUS CreateSparseImgFlashThread (IN FlashInfo* ThreadFlashInfo)
+{
+  EFI_STATUS Status = EFI_SUCCESS;
+  Thread* SparseImgFlashTD = NULL;
+
+  SparseImgFlashTD = KernIntf->Thread->ThreadCreate ("SparseImgFlashThread",
+      SparseImgFlashThread, (VOID*)ThreadFlashInfo, UEFI_THREAD_PRIORITY,
+      DEFAULT_STACK_SIZE);
+
+  if (SparseImgFlashTD == NULL) {
+    return EFI_NOT_READY;
+  }
+
+  AllocateUnSafeStackPtr (SparseImgFlashTD);
+
+  Status = KernIntf->Thread->ThreadResume (SparseImgFlashTD);
+  return Status;
+}
+
 #endif
 
 /* Handle Download Command */
@@ -1335,6 +1415,11 @@
 
   gBS->CopyMem (GetFastbootDeviceData ()->gTxBuffer, Response,
                 sizeof (Response));
+
+  if (IsUseMThreadParallel ()) {
+    KernIntf->Lock->AcquireLock (LockDownload);
+  }
+
   mState = ExpectDataState;
   mBytesReceivedSoFar = 0;
   GetFastbootDeviceData ()->UsbDeviceProtocol->Send (
@@ -1383,6 +1468,7 @@
     gBS->CloseEvent (UsbTimerEvent);
     UsbTimerEvent = NULL;
   }
+
   UsbTimerStarted = FALSE;
 }
 #else
@@ -1508,10 +1594,20 @@
 {
   VOID *mTmpbuff;
 
+  if (IsUseMThreadParallel ()) {
+    KernIntf->Lock->AcquireLock (LockDownload);
+    KernIntf->Lock->AcquireLock (LockFlash);
+  }
+
   mTmpbuff = mUsbDataBuffer;
   mUsbDataBuffer = mFlashDataBuffer;
   mFlashDataBuffer = mTmpbuff;
   mFlashNumDataBytes = mNumDataBytes;
+
+  if (IsUseMThreadParallel ()) {
+    KernIntf->Lock->ReleaseLock (LockFlash);
+    KernIntf->Lock->ReleaseLock (LockDownload);
+  }
 }
 
 STATIC EFI_STATUS
@@ -1754,29 +1850,54 @@
       goto out;
     }
 
-    IsFlashComplete = FALSE;
     PartitionSize = (BlockIo->Media->LastBlock + 1)
                         * (BlockIo->Media->BlockSize);
 
     if ((PartitionSize > MaxDownLoadSize) &&
          !IsDisableParallelDownloadFlash ()) {
-      Status = HandleUsbEventsInTimer ();
-      if (EFI_ERROR (Status)) {
-        DEBUG ((EFI_D_ERROR, "Failed to handle usb event: %r\n", Status));
-        IsFlashComplete = TRUE;
-        StopUsbTimer ();
+      if (IsUseMThreadParallel ()) {
+        FlashInfo* ThreadFlashInfo = AllocateZeroPool (sizeof (FlashInfo));
+        if (!ThreadFlashInfo) {
+          DEBUG ((EFI_D_ERROR,
+                  "ERROR: Failed to allocate memory for ThreadFlashInfo\n"));
+          return ;
+        }
+
+        ThreadFlashInfo->FlashDataBuffer = mFlashDataBuffer,
+        ThreadFlashInfo->FlashNumDataBytes = mFlashNumDataBytes;
+
+        StrnCpyS (ThreadFlashInfo->PartitionName, MAX_GPT_NAME_SIZE,
+                PartitionName, ARRAY_SIZE (PartitionName));
+        ThreadFlashInfo->PartitionSize = ARRAY_SIZE (PartitionName);
+
+        Status = CreateSparseImgFlashThread (ThreadFlashInfo);
       } else {
-        UsbTimerStarted = TRUE;
+        IsFlashComplete = FALSE;
+
+        Status = HandleUsbEventsInTimer ();
+        if (EFI_ERROR (Status)) {
+          DEBUG ((EFI_D_ERROR, "Failed to handle usb event: %r\n", Status));
+          IsFlashComplete = TRUE;
+          StopUsbTimer ();
+        } else {
+          UsbTimerStarted = TRUE;
+        }
+      }
+
+      if (!EFI_ERROR (Status)) {
         FastbootOkay ("");
       }
     }
 
-    FlashResult = HandleSparseImgFlash (PartitionName,
+    if (EFI_ERROR (Status) ||
+      !IsUseMThreadParallel () ||
+      (PartitionSize <= MaxDownLoadSize)) {
+      FlashResult = HandleSparseImgFlash (PartitionName,
                                         ARRAY_SIZE (PartitionName),
                                         mFlashDataBuffer, mFlashNumDataBytes);
-
-    IsFlashComplete = TRUE;
-    StopUsbTimer ();
+      IsFlashComplete = TRUE;
+      StopUsbTimer ();
+    }
   } else if (!AsciiStrnCmp (UbiHeader->HdrMagic, UBI_HEADER_MAGIC, 4)) {
     FlashResult = HandleUbiImgFlash (PartitionName,
                                      ARRAY_SIZE (PartitionName),
@@ -1851,6 +1972,8 @@
   CHAR8 EraseResultStr[MAX_RSP_SIZE] = "";
   VirtualAbMergeStatus SnapshotMergeStatus;
 
+  WaitForFlashFinished ();
+
   if (AsciiStrLen (arg) >= MAX_GPT_NAME_SIZE) {
     FastbootFail ("Invalid partition name");
     return;
@@ -2123,11 +2246,17 @@
       gBS->SetMem ((VOID *)(Data + mNumDataBytes), RoundSize - mNumDataBytes,
                    0);
     }
-    /* Stop usb timer after data transfer completed */
-    StopUsbTimer ();
-    /* Postpone Fastboot Okay until flash completed */
-    FastbootOkayDelay ();
     mState = ExpectCmdState;
+
+    if (IsUseMThreadParallel ())  {
+      KernIntf->Lock->ReleaseLock (LockDownload);
+      FastbootOkay ("");
+    } else {
+      /* Stop usb timer after data transfer completed */
+      StopUsbTimer ();
+      /* Postpone Fastboot Okay until flash completed */
+      FastbootOkayDelay ();
+    }
   } else {
     GetFastbootDeviceData ()->UsbDeviceProtocol->Send (
         ENDPOINT_IN, GetXfrSize (), (Data + mBytesReceivedSoFar));
@@ -2266,6 +2395,68 @@
   return;
 }
 
+//Shoud block command until flash finished
+VOID WaitForFlashFinished (VOID)
+{
+  if (!IsFlashComplete &&
+    IsUseMThreadParallel ()) {
+    KernIntf->Lock->AcquireLock (LockFlash);
+    KernIntf->Lock->ReleaseLock (LockFlash);
+  }
+}
+
+VOID ThreadSleep (TimeDuration Delay)
+{
+  KernIntf->Thread->ThreadSleep (Delay);
+}
+
+BOOLEAN IsUseMThreadParallel (VOID)
+{
+  if (FixedPcdGetBool (EnableMultiThreadFlash)) {
+    return IsMultiThreadSupported;
+  }
+
+  return FALSE;
+}
+
+VOID InitMultiThreadEnv ()
+{
+  EFI_STATUS Status = EFI_SUCCESS;
+
+  if (IsDisableParallelDownloadFlash ()) {
+    return;
+  }
+
+  Status = gBS->LocateProtocol (&gEfiKernelProtocolGuid, NULL,
+      (VOID **)&KernIntf);
+
+  if ((Status != EFI_SUCCESS) ||
+    (KernIntf == NULL) ||
+    KernIntf->Version < EFI_KERNEL_PROTOCOL_VER_UNSAFE_STACK_APIS) {
+    DEBUG ((EFI_D_VERBOSE, "Multi thread is not supported.\n"));
+    return;
+  }
+
+  KernIntf->Lock->InitLock ("DOWNLOAD", &LockDownload);
+  if (&LockDownload == NULL) {
+     DEBUG ((EFI_D_ERROR, "InitLock LockDownload error \n"));
+     return;
+  }
+
+  KernIntf->Lock->InitLock ("FLASH", &LockFlash);
+  if (&LockFlash == NULL) {
+    DEBUG ((EFI_D_ERROR, "InitLock LockFlash error \n"));
+    KernIntf->Lock->DestroyLock (LockDownload);
+    return;
+  }
+
+  //init MultiThreadEnv succeeded, use multi thread to flash
+  IsMultiThreadSupported = TRUE;
+
+  DEBUG ((EFI_D_VERBOSE,
+          "InitMultiThreadEnv successfully, will use thread to flash \n"));
+}
+
 EFI_STATUS
 FastbootCmdsInit (VOID)
 {
@@ -2338,6 +2529,9 @@
                               MaxDownLoadSize : MaxDownLoadSize / 2;
 
   FastbootCommandSetup ((VOID *)FastBootBuffer, MaxDownLoadSize);
+
+  InitMultiThreadEnv ();
+
   return EFI_SUCCESS;
 }
 
@@ -3116,7 +3310,8 @@
     /* Wait for flash finished before next command */
     if (AsciiStrnCmp (Data, "download", AsciiStrLen ("download"))) {
       StopUsbTimer ();
-      if (!IsFlashComplete) {
+      if (!IsFlashComplete &&
+          !IsUseMThreadParallel ()) {
         Status = AcceptCmdTimerInit (Size, Data);
         if (Status == EFI_SUCCESS) {
           return;
diff --git a/QcomModulePkg/Library/FastbootLib/FastbootCmds.h b/QcomModulePkg/Library/FastbootLib/FastbootCmds.h
old mode 100644
new mode 100755
index 57ec9a5..7fb91c1
--- a/QcomModulePkg/Library/FastbootLib/FastbootCmds.h
+++ b/QcomModulePkg/Library/FastbootLib/FastbootCmds.h
@@ -2,7 +2,7 @@
  * Copyright (c) 2009, Google Inc.
  * All rights reserved.
  *
- * Copyright (c) 2015-2018, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2015-2018, 2020, The Linux Foundation. All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions are
@@ -38,6 +38,7 @@
 #include <Library/LinuxLoaderLib.h>
 #include <Library/MemoryAllocationLib.h>
 #include <Library/PartitionTableUpdate.h>
+#include <Protocol/EFIKernelInterface.h>
 
 #define ENDPOINT_IN 0x01
 #define ENDPOINT_OUT 0x81
@@ -173,5 +174,10 @@
 UpdateDevInfo (CHAR16 *Pname, CHAR8 *ImgVersion);
 VOID
 GetDevInfo (DeviceInfo **DevinfoPtr);
-BOOLEAN IsUsbTimerStarted (VOID);
+BOOLEAN IsFlashSplitNeeded (VOID);
+BOOLEAN FlashComplete (VOID);
+BOOLEAN IsDisableParallelDownloadFlash (VOID);
+BOOLEAN IsUseMThreadParallel (VOID);
+VOID ThreadSleep (TimeDuration Delay);
+VOID WaitForFlashFinished (VOID);
 #endif
diff --git a/QcomModulePkg/Library/FastbootLib/FastbootLib.inf b/QcomModulePkg/Library/FastbootLib/FastbootLib.inf
index b371aa1..54698ea 100644
--- a/QcomModulePkg/Library/FastbootLib/FastbootLib.inf
+++ b/QcomModulePkg/Library/FastbootLib/FastbootLib.inf
@@ -1,5 +1,5 @@
 #/*
-# * Copyright (c) 2015-2019, The Linux Foundation. All rights reserved.
+# * Copyright (c) 2015-2020, The Linux Foundation. All rights reserved.
 # *
 # * Redistribution and use in source and binary forms, with or without
 # * modification, are permitted provided that the following conditions are
@@ -99,3 +99,4 @@
 [FixedPcd]
   gQcomTokenSpaceGuid.EnableMdtpSupport
   gQcomTokenSpaceGuid.EnableBatteryVoltageCheck
+  gQcomTokenSpaceGuid.EnableMultiThreadFlash
diff --git a/QcomModulePkg/Library/FastbootLib/FastbootMain.c b/QcomModulePkg/Library/FastbootLib/FastbootMain.c
index 4ba5354..ae01672 100755
--- a/QcomModulePkg/Library/FastbootLib/FastbootMain.c
+++ b/QcomModulePkg/Library/FastbootLib/FastbootMain.c
@@ -14,7 +14,7 @@
 
 **/
 
-/* Copyright (c) 2015-2019, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2015-2020, The Linux Foundation. All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions are
diff --git a/QcomModulePkg/Library/avb/VerifiedBoot.c b/QcomModulePkg/Library/avb/VerifiedBoot.c
old mode 100644
new mode 100755
index 0d3540c..d276294
--- a/QcomModulePkg/Library/avb/VerifiedBoot.c
+++ b/QcomModulePkg/Library/avb/VerifiedBoot.c
@@ -31,6 +31,7 @@
 #include "BootImage.h"
 #include "KeymasterClient.h"
 #include "libavb/libavb.h"
+#include <FastbootLib/FastbootCmds.h>
 #include <Library/MenuKeysDetection.h>
 #include <Library/VerifiedBootMenu.h>
 #include <Library/LEOEMCertificate.h>
@@ -1133,6 +1134,8 @@
            IsDynamicPartitionSupport ()) &&
            (Info->BootIntoRecovery &&
            !IsBuildUseRecoveryAsBoot ())) {
+    if (!Info->MultiSlotBoot)
+              VerifyFlags = VerifyFlags | AVB_SLOT_VERIFY_FLAGS_NO_VBMETA_PARTITION;
     AddRequestedPartition (RequestedPartitionAll, IMG_RECOVERY);
     NumRequestedPartition += 1;
     Result = avb_slot_verify (Ops, (CONST CHAR8 *CONST *)RequestedPartition,
@@ -1579,6 +1582,8 @@
   QCOM_MDTP_PROTOCOL *MdtpProtocol;
   UINT32 AVBVersion = NO_AVB;
 
+  WaitForFlashFinished ();
+
   if (Info == NULL) {
     DEBUG ((EFI_D_ERROR, "Invalid parameter Info\n"));
     return EFI_INVALID_PARAMETER;
diff --git a/QcomModulePkg/Library/avb/libavb/avb_ops.c b/QcomModulePkg/Library/avb/libavb/avb_ops.c
index 0afd22b..1fe1258 100644
--- a/QcomModulePkg/Library/avb/libavb/avb_ops.c
+++ b/QcomModulePkg/Library/avb/libavb/avb_ops.c
@@ -117,14 +117,6 @@
         EFI_GUID *Guid;
 }AvbPartitionDetails;
 
-static AvbPartitionDetails SupportedPartitions[] =
-{
-  { "vbmeta", &gEfiVbmetaPartitionGuid },
-  { "boot", &gEfiBootImgPartitionGuid },
-  { "dtbo", &gEfiDtboPartitionGuid },
-  { "recovery", &gEfiRecoveryImgPartitionGuid} ,
-};
-
 AvbIOResult AvbReadFromPartition(AvbOps *Ops, const char *Partition, int64_t ReadOffset,
                      size_t NumBytes, void *Buffer, size_t *OutNumRead)
 {
@@ -140,12 +132,6 @@
         UINT64 LastBlock = 0;
         UINT64 FullBlock = 0;
         UINT64 StartPageReadSize = 0;
-        UINT32 BlkIOAttrib = 0;
-        PartiSelectFilter HandleFilter;
-        UINT32 MaxHandles = 0;
-        AvbPartitionDetails *List = SupportedPartitions;
-        UINT32 Count = ARRAY_SIZE (SupportedPartitions);
-        EFI_GUID *PType = NULL;
         UINT64 LoadImageStartTime = GetTimerCountms ();
 
 	if (Partition == NULL || Buffer == NULL || OutNumRead == NULL || NumBytes <= 0) {
@@ -155,57 +141,13 @@
 	}
 	*OutNumRead = 0;
 
-        for (size_t Index = 0; Index < Count; Index++) {
-                if (!AsciiStrCmp (List[Index].Name, Partition)) {
-                             DEBUG ((EFI_D_INFO,
-                                  "Partition found: %a\n", Partition));
-                             PType = List[Index].Guid;
-                 }
+        Result = GetHandleInfo (Partition, InfoList);
+        if (Result != AVB_IO_RESULT_OK) {
+                DEBUG ((EFI_D_ERROR,
+                        "AvbGetSizeOfPartition: GetHandleInfo failed"));
+                goto out;
         }
 
-        if (PType) {
-                BlkIOAttrib = BLK_IO_SEL_PARTITIONED_GPT;
-                BlkIOAttrib |= BLK_IO_SEL_MEDIA_TYPE_NON_REMOVABLE;
-                BlkIOAttrib |= BLK_IO_SEL_MATCH_PARTITION_TYPE_GUID;
-
-                HandleFilter.RootDeviceType = NULL;
-                HandleFilter.PartitionType = PType;
-                HandleFilter.VolumeName = NULL;
-
-                MaxHandles = ARRAY_SIZE (InfoList);
-
-                Status = GetBlkIOHandles (BlkIOAttrib, &HandleFilter,
-                           InfoList, &MaxHandles);
-                if (Status == EFI_SUCCESS) {
-                        if (MaxHandles == 0) {
-                            DEBUG ((EFI_D_INFO,
-                            "Partition Not found: %s\n", Partition));
-                            Result = AVB_IO_RESULT_ERROR_NO_SUCH_PARTITION;
-                            goto out;
-                }
-
-                if (MaxHandles != 1) {
-                /* Unable to deterministically load from single partition */
-                             DEBUG ((EFI_D_INFO,
-                             "multiple partitions found: %s\n", Partition));
-                              Result = AVB_IO_RESULT_ERROR_IO;
-                              goto out;
-                     }
-                 } else {
-                      DEBUG ((EFI_D_INFO,
-                       "GetBlkIOHandles failed with error: %d\n", Status));
-                        Result = AVB_IO_RESULT_ERROR_IO;
-                        goto out;
-               }
-          } else {
-                Result = GetHandleInfo (Partition, InfoList);
-                if (Result != AVB_IO_RESULT_OK) {
-                      DEBUG ((EFI_D_ERROR,
-                       "AvbGetSizeOfPartition: GetHandleInfo failed"));
-                      goto out;
-           }
-       }
-
 	BlockIo = InfoList[0].BlkIo;
 	PartitionSize = (BlockIo->Media->LastBlock + 1) * BlockIo->Media->BlockSize;
 
@@ -428,6 +370,34 @@
 	return AVB_IO_RESULT_OK;
 }
 
+
+AvbIOResult
+AvbValidatePartitionPublicKey(AvbOps *Ops, const char* Partition,
+                           const uint8_t *PublicKeyData, size_t PublicKeyLength,
+                           const uint8_t *PublicKeyMetadata, size_t PublicKeyMetadataLength,
+                           bool *OutIsTrusted, uint32_t* OutRollbackIndexLocation)
+{
+	DEBUG((EFI_D_VERBOSE, "ValidatePartitionPublicKey PublicKeyLength %d, "
+	                      "PublicKeyMetadataLength %d\n",
+	       PublicKeyLength, PublicKeyMetadataLength));
+
+	if (OutIsTrusted == NULL || PublicKeyData == NULL) {
+		DEBUG((EFI_D_ERROR, "Invalid parameters\n"));
+		return AVB_IO_RESULT_ERROR_IO;
+	}
+
+	if (PublicKeyLength == ARRAY_SIZE(OEMPublicKey) &&
+	           CompareMem(PublicKeyData, OEMPublicKey, PublicKeyLength) == 0) {
+		*OutIsTrusted = true;
+	} else {
+		*OutIsTrusted = false;
+	}
+	*OutRollbackIndexLocation = 1; // Recovery rollback index
+	DEBUG((EFI_D_ERROR,
+	       "ValidateVbmetaPublicKey OutIsTrusted %d\n",*OutIsTrusted));
+	return AVB_IO_RESULT_OK;
+}
+
 AvbIOResult AvbReadRollbackIndex(AvbOps *Ops, size_t RollbackIndexLocation,
                                  uint64_t *OutRollbackIndex)
 {
@@ -603,6 +573,7 @@
 	Ops->read_from_partition = AvbReadFromPartition;
 	Ops->write_to_partition = AvbWriteToPartition;
 	Ops->validate_vbmeta_public_key = AvbValidateVbmetaPublicKey;
+	Ops->validate_public_key_for_partition = AvbValidatePartitionPublicKey;
 	Ops->read_rollback_index = AvbReadRollbackIndex;
 	Ops->write_rollback_index = AvbWriteRollbackIndex;
 	Ops->read_is_device_unlocked = AvbReadIsDeviceUnlocked;
diff --git a/QcomModulePkg/Library/avb/libavb/avb_ops.h b/QcomModulePkg/Library/avb/libavb/avb_ops.h
index 8162194..76cc9d4 100644
--- a/QcomModulePkg/Library/avb/libavb/avb_ops.h
+++ b/QcomModulePkg/Library/avb/libavb/avb_ops.h
@@ -155,6 +155,10 @@
    *
    * If AVB_IO_RESULT_OK is returned then |out_is_trusted| is set -
    * true if trusted or false if untrusted.
+   *
+   * NOTE: If AVB_SLOT_VERIFY_FLAGS_NO_VBMETA_PARTITION is passed to
+   * avb_slot_verify() then this operation is never used. Instead, the
+   * validate_public_key_for_partition() operation is used
    */
   AvbIOResult (*validate_vbmeta_public_key)(AvbOps* ops,
                                             const uint8_t* public_key_data,
@@ -223,6 +227,26 @@
   AvbIOResult (*get_size_of_partition)(AvbOps* ops,
                                        const char* partition,
                                        uint64_t* out_size_num_bytes);
+
+  /* Like validate_vbmeta_public_key() but for when the flag
+   * AVB_SLOT_VERIFY_FLAGS_NO_VBMETA_PARTITION is being used. The name of the
+   * partition to get the public key for is passed in |partition_name|.
+   *
+   * Also returns the rollback index location to use for the partition, in
+   * |out_rollback_index_location|.
+   *
+   * Returns AVB_IO_RESULT_OK on success, otherwise an error code.
+   */
+  AvbIOResult (*validate_public_key_for_partition)(
+      AvbOps* ops,
+      const char* partition,
+      const uint8_t* public_key_data,
+      size_t public_key_length,
+      const uint8_t* public_key_metadata,
+      size_t public_key_metadata_length,
+      bool* out_is_trusted,
+      uint32_t* out_rollback_index_location);
+
 };
 
 typedef struct {
diff --git a/QcomModulePkg/Library/avb/libavb/avb_slot_verify.c b/QcomModulePkg/Library/avb/libavb/avb_slot_verify.c
index fb6fc79..180e2d4 100644
--- a/QcomModulePkg/Library/avb/libavb/avb_slot_verify.c
+++ b/QcomModulePkg/Library/avb/libavb/avb_slot_verify.c
@@ -359,6 +359,7 @@
     AvbOps* ops,
     const char* const* requested_partitions,
     const char* ab_suffix,
+    AvbSlotVerifyFlags flags,
     bool allow_verification_error,
     AvbVBMetaImageFlags toplevel_vbmeta_flags,
     int rollback_index_location,
@@ -398,7 +399,12 @@
    * rollback_index_location to determine whether we're the main
    * vbmeta struct.
    */
-  is_main_vbmeta = (rollback_index_location == 0);
+  is_main_vbmeta = false;
+  if (rollback_index_location == 0) {
+    if ((flags & AVB_SLOT_VERIFY_FLAGS_NO_VBMETA_PARTITION) == 0) {
+      is_main_vbmeta = true;
+    }
+  }
 
   /* Don't use footers for vbmeta partitions ('vbmeta' or
    * 'vbmeta_<partition_name>').
@@ -509,6 +515,7 @@
       ret = load_and_verify_vbmeta(ops,
                                    requested_partitions,
                                    ab_suffix,
+                                   flags,
                                    allow_verification_error,
                                    0 /* toplevel_vbmeta_flags */,
                                    0 /* rollback_index_location */,
@@ -585,6 +592,8 @@
     }
   }
 
+  uint32_t rollback_index_location_to_use = rollback_index_location;
+
   /* Check if key used to make signature matches what is expected. */
   if (pk_data != NULL) {
     if (expected_public_key != NULL) {
@@ -612,9 +621,27 @@
         pk_metadata_len = vbmeta_header.public_key_metadata_size;
       }
 
-      avb_assert(is_main_vbmeta);
-      io_ret = ops->validate_vbmeta_public_key(
-          ops, pk_data, pk_len, pk_metadata, pk_metadata_len, &key_is_trusted);
+      // If we're not using a vbmeta partition, need to use another AvbOps...
+      if (flags & AVB_SLOT_VERIFY_FLAGS_NO_VBMETA_PARTITION) {
+        io_ret = ops->validate_public_key_for_partition(
+            ops,
+            full_partition_name,
+            pk_data,
+            pk_len,
+            pk_metadata,
+            pk_metadata_len,
+            &key_is_trusted,
+            &rollback_index_location_to_use);
+      } else {
+        avb_assert(is_main_vbmeta);
+        io_ret = ops->validate_vbmeta_public_key(ops,
+                                                 pk_data,
+                                                 pk_len,
+                                                 pk_metadata,
+                                                 pk_metadata_len,
+                                                 &key_is_trusted);
+      }
+
       if (io_ret == AVB_IO_RESULT_ERROR_OOM) {
         ret = AVB_SLOT_VERIFY_RESULT_ERROR_OOM;
         goto out;
@@ -639,7 +666,7 @@
 
   /* Check rollback index. */
   io_ret = ops->read_rollback_index(
-      ops, rollback_index_location, &stored_rollback_index);
+      ops, rollback_index_location_to_use, &stored_rollback_index);
   if (io_ret == AVB_IO_RESULT_ERROR_OOM) {
     ret = AVB_SLOT_VERIFY_RESULT_ERROR_OOM;
     goto out;
@@ -679,7 +706,9 @@
   if (is_main_vbmeta) {
     avb_assert(slot_data->num_vbmeta_images == 0);
   } else {
-    avb_assert(slot_data->num_vbmeta_images > 0);
+    if (!(flags & AVB_SLOT_VERIFY_FLAGS_NO_VBMETA_PARTITION)) {
+      avb_assert(slot_data->num_vbmeta_images > 0);
+    }
   }
   if (slot_data->num_vbmeta_images == MAX_NUMBER_OF_VBMETA_IMAGES) {
     avb_errorv(full_partition_name, ": Too many vbmeta images.\n", NULL);
@@ -804,6 +833,7 @@
         sub_ret = load_and_verify_vbmeta(ops,
                                          requested_partitions,
                                          ab_suffix,
+                                         flags,
                                          allow_verification_error,
                                          toplevel_vbmeta_flags,
                                          chain_desc.rollback_index_location,
@@ -1003,6 +1033,16 @@
     }
   }
 
+  /* It's possible there is no _PARTUUID for replacement above.
+   * Duplicate cmdline to ret for additional substitutions below.
+   */
+  if (ret == NULL) {
+    ret = avb_strdup(cmdline);
+    if (ret == NULL) {
+      goto fail;
+    }
+  }
+
   return ret;
 
 fail:
@@ -1127,6 +1167,7 @@
 
 static AvbSlotVerifyResult append_options(
     AvbOps* ops,
+    AvbSlotVerifyFlags flags,
     AvbSlotVerifyData* slot_data,
     AvbVBMetaImageHeader* toplevel_vbmeta,
     AvbAlgorithmType algorithm_type,
@@ -1144,6 +1185,18 @@
     goto out;
   }
 
+  /* Add androidboot.vbmeta.device option... except if not using a vbmeta
+   * partition since it doesn't make sense in that case.
+   */
+  if (!(flags & AVB_SLOT_VERIFY_FLAGS_NO_VBMETA_PARTITION)) {
+    if (!cmdline_append_option(slot_data,
+                               "androidboot.vbmeta.device",
+                               "PARTUUID=$(ANDROID_VBMETA_PARTUUID)")) {
+      ret = AVB_SLOT_VERIFY_RESULT_ERROR_OOM;
+      goto out;
+    }
+  }
+
   /* Add androidboot.vbmeta.avb_version option. */
   if (!cmdline_append_version(slot_data,
                               "androidboot.vbmeta.avb_version",
@@ -1334,10 +1387,9 @@
   avb_assert(ops->read_is_device_unlocked != NULL);
   avb_assert(ops->read_from_partition != NULL);
   avb_assert(ops->get_size_of_partition != NULL);
-  avb_assert(ops->validate_vbmeta_public_key != NULL);
   avb_assert(ops->read_rollback_index != NULL);
   avb_assert(ops->get_unique_guid_for_partition != NULL);
-  /* avb_assert(ops->get_size_of_partition != NULL); */
+  avb_assert(ops->validate_public_key_for_partition != NULL);
 
   if (out_data != NULL) {
     *out_data = NULL;
@@ -1353,6 +1405,21 @@
     goto fail;
   }
 
+  /* Make sure passed-in AvbOps support verifying public keys and getting
+   * rollback index location if not using a vbmeta partition.
+   */
+  if (flags & AVB_SLOT_VERIFY_FLAGS_NO_VBMETA_PARTITION) {
+    if (ops->validate_public_key_for_partition == NULL) {
+      avb_error(
+          "AVB_SLOT_VERIFY_FLAGS_NO_VBMETA_PARTITION was passed but the "
+          "validate_public_key_for_partition() operation isn't implemented.\n");
+      ret = AVB_SLOT_VERIFY_RESULT_ERROR_INVALID_ARGUMENT;
+      goto fail;
+    }
+  } else {
+    avb_assert(ops->validate_vbmeta_public_key != NULL);
+  }
+
   slot_data = avb_calloc(sizeof(AvbSlotVerifyData));
   if (slot_data == NULL) {
     ret = AVB_SLOT_VERIFY_RESULT_ERROR_OOM;
@@ -1371,30 +1438,67 @@
     goto fail;
   }
 
-  ret = load_and_verify_vbmeta(ops,
-                               requested_partitions,
-                               ab_suffix,
-                               allow_verification_error,
-                               0 /* toplevel_vbmeta_flags */,
-                               0 /* rollback_index_location */,
-                               "vbmeta",
-                               avb_strlen("vbmeta"),
-                               NULL /* expected_public_key */,
-                               0 /* expected_public_key_length */,
-                               slot_data,
-                               &algorithm_type);
-  if ((!allow_verification_error && ret != AVB_SLOT_VERIFY_RESULT_OK) ||
-      !result_should_continue(ret)) {
+  if (flags & AVB_SLOT_VERIFY_FLAGS_NO_VBMETA_PARTITION) {
+    if (requested_partitions == NULL || requested_partitions[0] == NULL) {
+      avb_fatal(
+          "Requested partitions cannot be empty when using "
+          "AVB_SLOT_VERIFY_FLAGS_NO_VBMETA_PARTITION");
+      ret = AVB_SLOT_VERIFY_RESULT_ERROR_INVALID_ARGUMENT;
+      goto fail;
+    }
+
+    /* No vbmeta partition, go through each of the requested partitions... */
+    for (size_t n = 0; requested_partitions[n] != NULL; n++) {
+      ret = load_and_verify_vbmeta(ops,
+                                   requested_partitions,
+                                   ab_suffix,
+                                   flags,
+                                   allow_verification_error,
+                                   0 /* toplevel_vbmeta_flags */,
+                                   0 /* rollback_index_location */,
+                                   requested_partitions[n],
+                                   avb_strlen(requested_partitions[n]),
+                                   NULL /* expected_public_key */,
+                                   0 /* expected_public_key_length */,
+                                   slot_data,
+                                   &algorithm_type);
+      if (!allow_verification_error && ret != AVB_SLOT_VERIFY_RESULT_OK) {
+        goto fail;
+      }
+    }
+
+  } else {
+    /* Usual path, load "vbmeta"... */
+    ret = load_and_verify_vbmeta(ops,
+                                 requested_partitions,
+                                 ab_suffix,
+                                 flags,
+                                 allow_verification_error,
+                                 0 /* toplevel_vbmeta_flags */,
+                                 0 /* rollback_index_location */,
+                                 "vbmeta",
+                                 avb_strlen("vbmeta"),
+                                 NULL /* expected_public_key */,
+                                 0 /* expected_public_key_length */,
+                                 slot_data,
+                                 &algorithm_type);
+    if (!allow_verification_error && ret != AVB_SLOT_VERIFY_RESULT_OK) {
+      goto fail;
+    }
+  }
+
+  if (!result_should_continue(ret)) {
     goto fail;
   }
 
   /* If things check out, mangle the kernel command-line as needed. */
-  if (result_should_continue(ret)) {
+  if (!(flags & AVB_SLOT_VERIFY_FLAGS_NO_VBMETA_PARTITION)) {
     if (avb_strcmp(slot_data->vbmeta_images[0].partition_name, "vbmeta") != 0) {
       avb_assert(
           avb_strcmp(slot_data->vbmeta_images[0].partition_name, "boot") == 0);
       using_boot_for_vbmeta = true;
     }
+  }
 
     /* Byteswap top-level vbmeta header since we'll need it below. */
     avb_vbmeta_image_header_to_host_byte_order(
@@ -1437,6 +1541,7 @@
        * I/O or OOM error.
        */
       AvbSlotVerifyResult sub_ret = append_options(ops,
+                                                   flags,
                                                    slot_data,
                                                    &toplevel_vbmeta,
                                                    algorithm_type,
@@ -1464,7 +1569,6 @@
     } else {
       avb_slot_verify_data_free(slot_data);
     }
-  }
 
   if (!allow_verification_error) {
     avb_assert(ret == AVB_SLOT_VERIFY_RESULT_OK);
diff --git a/QcomModulePkg/Library/avb/libavb/avb_slot_verify.h b/QcomModulePkg/Library/avb/libavb/avb_slot_verify.h
index 2d460fc..9485e8e 100644
--- a/QcomModulePkg/Library/avb/libavb/avb_slot_verify.h
+++ b/QcomModulePkg/Library/avb/libavb/avb_slot_verify.h
@@ -99,10 +99,21 @@
  * contents loaded from |requested_partition| will be the contents of
  * the entire partition instead of just the size specified in the hash
  * descriptor.
+ *
+ * If the AVB_SLOT_VERIFY_FLAGS_NO_VBMETA_PARTITION flag is set then
+ * data won't be loaded from the "vbmeta" partition and the
+ * |validate_vbmeta_public_key| operation is never called. Instead, the
+ * vbmeta structs in |requested_partitions| are loaded and processed and the
+ * |validate_public_key_for_partition| operation is called for each of these
+ * vbmeta structs. This flag is useful when booting into recovery on a device
+ * not using A/B - see section "Booting into recovery" in README.md for
+ * more information.
  */
 typedef enum {
   AVB_SLOT_VERIFY_FLAGS_NONE = 0,
-  AVB_SLOT_VERIFY_FLAGS_ALLOW_VERIFICATION_ERROR = (1 << 0)
+  AVB_SLOT_VERIFY_FLAGS_ALLOW_VERIFICATION_ERROR = (1 << 0),
+  AVB_SLOT_VERIFY_FLAGS_RESTART_CAUSED_BY_HASHTREE_CORRUPTION = (1 << 1),
+  AVB_SLOT_VERIFY_FLAGS_NO_VBMETA_PARTITION = (1 << 2),
 } AvbSlotVerifyFlags;
 
 /* Get a textual representation of |result|. */
@@ -215,7 +226,9 @@
  *   PARTUUID=$(ANDROID_VBMETA_PARTUUID) before substitution so it
  *   will end up pointing to the vbmeta partition for the verified
  *   slot. If there is no vbmeta partition it will point to the boot
- *   partition of the verified slot.
+ *   partition of the verified slot. If the flag
+ *   AVB_SLOT_VERIFY_FLAGS_NO_VBMETA_PARTITION is used, this is not
+ *   set.
  *
  *   androidboot.vbmeta.avb_version: This is set to the decimal value
  *   of AVB_VERSION_MAJOR followed by a dot followed by the decimal
diff --git a/QcomModulePkg/QcomModulePkg.dec b/QcomModulePkg/QcomModulePkg.dec
index c3baa60..51d6490 100644
--- a/QcomModulePkg/QcomModulePkg.dec
+++ b/QcomModulePkg/QcomModulePkg.dec
@@ -142,6 +142,8 @@
   gEfiDDRGetInfoProtocolGuid =         { 0x1a7c0eb8, 0x5646, 0x45f7, { 0xab, 0x20, 0xea, 0xe5, 0xda, 0x46, 0x40, 0xa2 } }
   # Display Utils Protocol
   gQcomDisplayUtilsProtocolGuid =      { 0xc0dd69ac, 0x76ba, 0x11e6, { 0xab, 0x24, 0x1f, 0xc7, 0xf5, 0x57, 0x5f, 0x19 } }
+  # Multithreading Kernel protocol for UEFI
+  gEfiKernelProtocolGuid =             { 0xB5062BE7, 0x170B, 0x4A32, { 0xBE, 0x21, 0x68, 0x92, 0x62, 0xFF, 0x43, 0x99 } }
 
 [PcdsFixedAtBuild.common]
   # LinuxLoaderCommon
@@ -157,3 +159,4 @@
   gQcomTokenSpaceGuid.EnableBatteryVoltageCheck|TRUE|BOOLEAN|0x00015009
   gQcomTokenSpaceGuid.RamdiskEndAddress32|0x03C00000|UINT32|0x0001500A
   gQcomTokenSpaceGuid.EnableNewNodeSearchFuc|TRUE|BOOLEAN|0x0001500B
+  gQcomTokenSpaceGuid.EnableMultiThreadFlash|TRUE|BOOLEAN|0x0001500C