From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from mail-pg1-f170.google.com (mail-pg1-f170.google.com [209.85.215.170]) by mx.groups.io with SMTP id smtpd.web10.7866.1608285866064200125 for ; Fri, 18 Dec 2020 02:04:26 -0800 Authentication-Results: mx.groups.io; dkim=pass header.i=@linaro.org header.s=google header.b=xqoavhN+; spf=pass (domain: linaro.org, ip: 209.85.215.170, mailfrom: masahisa.kojima@linaro.org) Received: by mail-pg1-f170.google.com with SMTP id w5so1031483pgj.3 for ; Fri, 18 Dec 2020 02:04:26 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linaro.org; s=google; h=from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; bh=6yH1DtUIfYiXxW56OnmIJgIxLpLC3GNfOmmpTadBb8U=; b=xqoavhN+50ik8nOMaluSBZr5qOTBwvzhrvt29w49Wfd3qUKmMjI62xHk28Ue+Q8ZEO onevpir5/JQSjW4c/s3e55P6OMb16oItDxc+1ZlEq2uYE0SNVFP0PAAojrSVAQIyFnfA R9CJG7IMEU9To+SdC8bSGMDgSOFeL+Iw8B+BVbhYRbtSpohxZ1ido2VSWfWEPBl0bDA3 E9jnlKA9l9/naMqUUFts8hSu95hXQ+IMgjhdK4zPzTKyvmz+ixfLYzXOcVpwISNtn3MR /zA74AQu/uI7zBTo7wKwgxGrnZFX38RKL9556DYYyfQ5Rh6mtX8fZKz6nLpBpaTWe+dT IlMg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=6yH1DtUIfYiXxW56OnmIJgIxLpLC3GNfOmmpTadBb8U=; b=YOCSeHzD+6nIibrZgcy32cFCNe8AXKSBpf/BhIHmai4CQKvHwAV996GdQaTx625vWS 1SX1dbnOqYD25Sl2RdwzTIyhDX7uy8Bz72DQzypx/Dn6drYnT82fKymKdtuhRTu1vI/m PGs+T/VfKJDMvZ55TXASV9hDgrIBWUZ/WmeDaLjtwdtuxqWM2poN8lV58EYm6wErpr0L vYpS2yLflWtcsD9tcUp5QpsMZMmpYj5YY5EdI7gVEmQm+bncRkCjuGYZAY0r+IK5IHxA 7js+Ie6TeKES9d3nfnpoDjEBp8lYshLg+yw9awCnXrEfFMJ7dJoBxiAcp6Xze/O1pstG ZawA== X-Gm-Message-State: AOAM530b1vsaquexUYRb7aNLqFSnSkNsTWBmam3Kdm/M2dp2CP1TjRDW cBZ/m6Wpi77hFAuOTcS0brxQPtxRg7Z2wA== X-Google-Smtp-Source: ABdhPJwZzw5o73z+5pSh71mH2UcOXNDZrrZAJMK074Q5I1hyJ7m1LxjF5NQdDG7kVMVUD/xi0NaYSw== X-Received: by 2002:aa7:83cd:0:b029:1a5:fb23:ad7f with SMTP id j13-20020aa783cd0000b02901a5fb23ad7fmr3546486pfn.46.1608285865083; Fri, 18 Dec 2020 02:04:25 -0800 (PST) Return-Path: Received: from localhost ([121.95.100.191]) by smtp.gmail.com with ESMTPSA id a8sm8142136pfo.209.2020.12.18.02.04.23 (version=TLS1_2 cipher=ECDHE-ECDSA-CHACHA20-POLY1305 bits=256/256); Fri, 18 Dec 2020 02:04:24 -0800 (PST) From: "Masahisa Kojima" To: devel@edk2.groups.io Cc: Masahisa Kojima , Leif Lindholm , Ard Biesheuvel , Sami Mujawar , Jiewen Yao , Supreeth Venkatesh Subject: [PATCH 2/2] ArmPlatformPkg/NorFlashDxe: implement standalone MM version Date: Fri, 18 Dec 2020 19:05:16 +0900 Message-Id: <20201218100516.14149-3-masahisa.kojima@linaro.org> X-Mailer: git-send-email 2.17.1 In-Reply-To: <20201218100516.14149-1-masahisa.kojima@linaro.org> References: <20201218100516.14149-1-masahisa.kojima@linaro.org> MIME-Version: 1.0 Content-Transfer-Encoding: 8bit Implement a version of the NOR Flash driver that can execute in standalone MM context. This is used to access the secure variable storage, it only supports EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL. Signed-off-by: Masahisa Kojima Cc: Leif Lindholm Cc: Ard Biesheuvel Cc: Sami Mujawar Cc: Jiewen Yao Cc: Supreeth Venkatesh --- ArmPlatformPkg/Drivers/NorFlashDxe/NorFlashStandaloneMm.inf | 63 ++++ ArmPlatformPkg/Drivers/NorFlashDxe/NorFlashStandaloneMm.c | 364 ++++++++++++++++++++ 2 files changed, 427 insertions(+) diff --git a/ArmPlatformPkg/Drivers/NorFlashDxe/NorFlashStandaloneMm.inf b/ArmPlatformPkg/Drivers/NorFlashDxe/NorFlashStandaloneMm.inf new file mode 100644 index 000000000000..f788472406b7 --- /dev/null +++ b/ArmPlatformPkg/Drivers/NorFlashDxe/NorFlashStandaloneMm.inf @@ -0,0 +1,63 @@ +#/** @file +# +# Component description file for NorFlashStandaloneMm module +# +# Copyright (c) 2011 - 2014, ARM Ltd. All rights reserved.
+# Copyright (c) 2020, Linaro, Ltd. All rights reserved.
+# +# SPDX-License-Identifier: BSD-2-Clause-Patent +# +#**/ + +[Defines] + INF_VERSION = 0x00010005 + BASE_NAME = ArmVeNorFlashStandaloneMm + FILE_GUID = e67d82ad-cd56-4071-9151-95ee44990bb0 + MODULE_TYPE = MM_STANDALONE + VERSION_STRING = 1.0 + PI_SPECIFICATION_VERSION = 0x00010032 + ENTRY_POINT = NorFlashInitialise + +[Sources.common] + NorFlash.h + NorFlash.c + NorFlashStandaloneMm.c + NorFlashFvb.c + +[Packages] + MdePkg/MdePkg.dec + MdeModulePkg/MdeModulePkg.dec + ArmPlatformPkg/ArmPlatformPkg.dec + EmbeddedPkg/EmbeddedPkg.dec + StandaloneMmPkg/StandaloneMmPkg.dec + +[LibraryClasses] + BaseLib + BaseMemoryLib + DebugLib + IoLib + MemoryAllocationLib + MmServicesTableLib + NorFlashPlatformLib + StandaloneMmDriverEntryPoint + +[Guids] + gEfiSystemNvDataFvGuid + gEfiVariableGuid + gEfiAuthenticatedVariableGuid + +[Protocols] + gEfiSmmFirmwareVolumeBlockProtocolGuid + +[Pcd.common] + gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageVariableBase + gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageVariableSize + gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageFtwWorkingBase + gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageFtwWorkingSize + gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageFtwSpareBase + gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageFtwSpareSize + + gArmPlatformTokenSpaceGuid.PcdNorFlashCheckBlockLocked + +[Depex] + TRUE diff --git a/ArmPlatformPkg/Drivers/NorFlashDxe/NorFlashStandaloneMm.c b/ArmPlatformPkg/Drivers/NorFlashDxe/NorFlashStandaloneMm.c new file mode 100644 index 000000000000..1ebf6d6ba70b --- /dev/null +++ b/ArmPlatformPkg/Drivers/NorFlashDxe/NorFlashStandaloneMm.c @@ -0,0 +1,364 @@ +/** @file NorFlashStandaloneMm.c + + Copyright (c) 2011 - 2020, Arm Limited. All rights reserved.
+ Copyright (c) 2020, Linaro, Ltd. All rights reserved.
+ + SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include +#include +#include + +#include "NorFlash.h" + +// +// Global variable declarations +// +NOR_FLASH_INSTANCE **mNorFlashInstances; +UINT32 mNorFlashDeviceCount; +UINTN mFlashNvStorageVariableBase; + +NOR_FLASH_INSTANCE mNorFlashInstanceTemplate = { + NOR_FLASH_SIGNATURE, // Signature + NULL, // Handle ... NEED TO BE FILLED + + 0, // DeviceBaseAddress ... NEED TO BE FILLED + 0, // RegionBaseAddress ... NEED TO BE FILLED + 0, // Size ... NEED TO BE FILLED + 0, // StartLba + + { + EFI_BLOCK_IO_PROTOCOL_REVISION2, // Revision + NULL, // Media ... NEED TO BE FILLED + NULL, // Reset; + NULL, // ReadBlocks + NULL, // WriteBlocks + NULL // FlushBlocks + }, // BlockIoProtocol + + { + 0, // MediaId ... NEED TO BE FILLED + FALSE, // RemovableMedia + TRUE, // MediaPresent + FALSE, // LogicalPartition + FALSE, // ReadOnly + FALSE, // WriteCaching; + 0, // BlockSize ... NEED TO BE FILLED + 4, // IoAlign + 0, // LastBlock ... NEED TO BE FILLED + 0, // LowestAlignedLba + 1, // LogicalBlocksPerPhysicalBlock + }, //Media; + + { + EFI_DISK_IO_PROTOCOL_REVISION, // Revision + NULL, // ReadDisk + NULL // WriteDisk + }, + + { + FvbGetAttributes, // GetAttributes + FvbSetAttributes, // SetAttributes + FvbGetPhysicalAddress, // GetPhysicalAddress + FvbGetBlockSize, // GetBlockSize + FvbRead, // Read + FvbWrite, // Write + FvbEraseBlocks, // EraseBlocks + NULL, //ParentHandle + }, // FvbProtoccol; + NULL, // ShadowBuffer + { + { + { + HARDWARE_DEVICE_PATH, + HW_VENDOR_DP, + { + (UINT8)(OFFSET_OF (NOR_FLASH_DEVICE_PATH, End)), + (UINT8)(OFFSET_OF (NOR_FLASH_DEVICE_PATH, End) >> 8) + } + }, + { 0x0, 0x0, 0x0, { 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0 } }, // GUID ... NEED TO BE FILLED + }, + 0, // Index + { + END_DEVICE_PATH_TYPE, + END_ENTIRE_DEVICE_PATH_SUBTYPE, + { sizeof (EFI_DEVICE_PATH_PROTOCOL), 0 } + } + } // DevicePath +}; + +EFI_STATUS +NorFlashCreateInstance ( + IN UINTN NorFlashDeviceBase, + IN UINTN NorFlashRegionBase, + IN UINTN NorFlashSize, + IN UINT32 Index, + IN UINT32 BlockSize, + IN BOOLEAN SupportFvb, + OUT NOR_FLASH_INSTANCE** NorFlashInstance + ) +{ + EFI_STATUS Status; + NOR_FLASH_INSTANCE* Instance; + + ASSERT(NorFlashInstance != NULL); + + Instance = AllocateRuntimeCopyPool (sizeof(NOR_FLASH_INSTANCE),&mNorFlashInstanceTemplate); + if (Instance == NULL) { + return EFI_OUT_OF_RESOURCES; + } + + Instance->DeviceBaseAddress = NorFlashDeviceBase; + Instance->RegionBaseAddress = NorFlashRegionBase; + Instance->Size = NorFlashSize; + + Instance->BlockIoProtocol.Media = &Instance->Media; + Instance->Media.MediaId = Index; + Instance->Media.BlockSize = BlockSize; + Instance->Media.LastBlock = (NorFlashSize / BlockSize)-1; + + CopyGuid (&Instance->DevicePath.Vendor.Guid, &gEfiCallerIdGuid); + Instance->DevicePath.Index = (UINT8)Index; + + Instance->ShadowBuffer = AllocateRuntimePool (BlockSize);; + if (Instance->ShadowBuffer == NULL) { + return EFI_OUT_OF_RESOURCES; + } + + if (SupportFvb) { + NorFlashFvbInitialize (Instance); + + Status = gMmst->MmInstallProtocolInterface ( + &Instance->Handle, + &gEfiSmmFirmwareVolumeBlockProtocolGuid, + EFI_NATIVE_INTERFACE, + &Instance->FvbProtocol + ); + if (EFI_ERROR(Status)) { + FreePool (Instance); + return Status; + } + } else { + DEBUG((DEBUG_ERROR,"standalone MM NOR Flash driver only support FVB.\n")); + FreePool (Instance); + return EFI_UNSUPPORTED; + } + + *NorFlashInstance = Instance; + return Status; +} + +/** + * This function unlock and erase an entire NOR Flash block. + **/ +EFI_STATUS +NorFlashUnlockAndEraseSingleBlock ( + IN NOR_FLASH_INSTANCE *Instance, + IN UINTN BlockAddress + ) +{ + EFI_STATUS Status; + UINTN Index; + + Index = 0; + // The block erase might fail a first time (SW bug ?). Retry it ... + do { + // Unlock the block if we have to + Status = NorFlashUnlockSingleBlockIfNecessary (Instance, BlockAddress); + if (EFI_ERROR (Status)) { + break; + } + Status = NorFlashEraseSingleBlock (Instance, BlockAddress); + Index++; + } while ((Index < NOR_FLASH_ERASE_RETRY) && (Status == EFI_WRITE_PROTECTED)); + + if (Index == NOR_FLASH_ERASE_RETRY) { + DEBUG((DEBUG_ERROR,"EraseSingleBlock(BlockAddress=0x%08x: Block Locked Error (try to erase %d times)\n", BlockAddress,Index)); + } + + return Status; +} + +EFI_STATUS +NorFlashWriteFullBlock ( + IN NOR_FLASH_INSTANCE *Instance, + IN EFI_LBA Lba, + IN UINT32 *DataBuffer, + IN UINT32 BlockSizeInWords + ) +{ + EFI_STATUS Status; + UINTN WordAddress; + UINT32 WordIndex; + UINTN BufferIndex; + UINTN BlockAddress; + UINTN BuffersInBlock; + UINTN RemainingWords; + UINTN Cnt; + + Status = EFI_SUCCESS; + + // Get the physical address of the block + BlockAddress = GET_NOR_BLOCK_ADDRESS (Instance->RegionBaseAddress, Lba, BlockSizeInWords * 4); + + // Start writing from the first address at the start of the block + WordAddress = BlockAddress; + + Status = NorFlashUnlockAndEraseSingleBlock (Instance, BlockAddress); + if (EFI_ERROR(Status)) { + DEBUG((DEBUG_ERROR, "WriteSingleBlock: ERROR - Failed to Unlock and Erase the single block at 0x%X\n", BlockAddress)); + goto EXIT; + } + + // To speed up the programming operation, NOR Flash is programmed using the Buffered Programming method. + + // Check that the address starts at a 32-word boundary, i.e. last 7 bits must be zero + if ((WordAddress & BOUNDARY_OF_32_WORDS) == 0x00) { + + // First, break the entire block into buffer-sized chunks. + BuffersInBlock = (UINTN)(BlockSizeInWords * 4) / P30_MAX_BUFFER_SIZE_IN_BYTES; + + // Then feed each buffer chunk to the NOR Flash + // If a buffer does not contain any data, don't write it. + for(BufferIndex=0; + BufferIndex < BuffersInBlock; + BufferIndex++, WordAddress += P30_MAX_BUFFER_SIZE_IN_BYTES, DataBuffer += P30_MAX_BUFFER_SIZE_IN_WORDS + ) { + // Check the buffer to see if it contains any data (not set all 1s). + for (Cnt = 0; Cnt < P30_MAX_BUFFER_SIZE_IN_WORDS; Cnt++) { + if (~DataBuffer[Cnt] != 0 ) { + // Some data found, write the buffer. + Status = NorFlashWriteBuffer (Instance, WordAddress, P30_MAX_BUFFER_SIZE_IN_BYTES, + DataBuffer); + if (EFI_ERROR(Status)) { + goto EXIT; + } + break; + } + } + } + + // Finally, finish off any remaining words that are less than the maximum size of the buffer + RemainingWords = BlockSizeInWords % P30_MAX_BUFFER_SIZE_IN_WORDS; + + if(RemainingWords != 0) { + Status = NorFlashWriteBuffer (Instance, WordAddress, (RemainingWords * 4), DataBuffer); + if (EFI_ERROR(Status)) { + goto EXIT; + } + } + + } else { + // For now, use the single word programming algorithm + // It is unlikely that the NOR Flash will exist in an address which falls within a 32 word boundary range, + // i.e. which ends in the range 0x......01 - 0x......7F. + for(WordIndex=0; WordIndexStartLba = (PcdGet32 (PcdFlashNvStorageVariableBase) - Instance->RegionBaseAddress) / Instance->Media.BlockSize; + + // Determine if there is a valid header at the beginning of the NorFlash + Status = ValidateFvHeader (Instance); + + // Install the Default FVB header if required + if (EFI_ERROR(Status)) { + // There is no valid header, so time to install one. + DEBUG ((DEBUG_INFO, "%a: The FVB Header is not valid.\n", __FUNCTION__)); + DEBUG ((DEBUG_INFO, "%a: Installing a correct one for this volume.\n", + __FUNCTION__)); + + // Erase all the NorFlash that is reserved for variable storage + FvbNumLba = (PcdGet32(PcdFlashNvStorageVariableSize) + PcdGet32(PcdFlashNvStorageFtwWorkingSize) + PcdGet32(PcdFlashNvStorageFtwSpareSize)) / Instance->Media.BlockSize; + + Status = FvbEraseBlocks (&Instance->FvbProtocol, (EFI_LBA)0, FvbNumLba, EFI_LBA_LIST_TERMINATOR); + if (EFI_ERROR(Status)) { + return Status; + } + + // Install all appropriate headers + Status = InitializeFvAndVariableStoreHeaders (Instance); + if (EFI_ERROR(Status)) { + return Status; + } + } + + return Status; +} -- 2.17.1