From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from list by lists.gnu.org with archive (Exim 4.90_1) id 1lA7hi-00076p-Ob for mharc-grub-devel@gnu.org; Thu, 11 Feb 2021 03:52:02 -0500 Received: from eggs.gnu.org ([2001:470:142:3::10]:39374) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1lA7hg-00076H-7D for grub-devel@gnu.org; Thu, 11 Feb 2021 03:52:00 -0500 Received: from mout.gmx.net ([212.227.17.22]:56777) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1lA7hX-0004fr-Ua for grub-devel@gnu.org; Thu, 11 Feb 2021 03:52:00 -0500 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=gmx.net; s=badeba3b8450; t=1613033503; bh=hO1TdaJoQrndvPbv+1jA2L0JFC0p49yfHNsVqyQXuVI=; h=X-UI-Sender-Class:Subject:To:Cc:References:From:Date:In-Reply-To; b=lTSm787/gbhQev0YFi9+byx1HHDusDhS+mJ68kUdlzkxNk4bk6AM0/a4whabQpmMd UM/Rgykj6UHuXEKviqfYVoubbAZqbsiNBpPiYRc9kT/WtV2wWsVbIipqmk/J8UWf+P //Xk0wZf2YEZGJdQXXphJPCJXFgSLlg5KRAEOUh4= X-UI-Sender-Class: 01bb95c1-4bf8-414a-932a-4f6e2808ef9c Received: from [192.168.123.70] ([62.143.246.89]) by mail.gmx.net (mrgmx105 [212.227.17.168]) with ESMTPSA (Nemesis) id 1MsHru-1m3TVN2Lla-00toQs; Thu, 11 Feb 2021 09:51:43 +0100 Subject: Re: [PATCH v2 1/2] efi: SPI NOR flash support To: The development of GNU GRUB , Michael Lawnick , Michael Lawnick Cc: Paul Menzel References: <521ca300-6d1e-94ed-c87d-f4005a1f7870@gmx.de> From: Heinrich Schuchardt Message-ID: Date: Thu, 11 Feb 2021 09:51:35 +0100 User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:78.0) Gecko/20100101 Thunderbird/78.7.0 MIME-Version: 1.0 In-Reply-To: <521ca300-6d1e-94ed-c87d-f4005a1f7870@gmx.de> Content-Type: text/plain; charset=utf-8 Content-Language: en-US Content-Transfer-Encoding: quoted-printable X-Provags-ID: V03:K1:OHxCKmuaNF2JrV8e9TUWnB7+TOPjQnbs8x9U86cFNfNobzPW01N iKDx8hDNaUxVQoRR3rfSqp6q7LWBqh0TSMCEYkw1KQnLwj6GdFSjoHrHj6MCuXJqB65yrp7 cbZ0fu76GQ8xZxiSMyjEWD5PtoKhF/+JmleB+6aQa2SZF5S5V91ukImPCiF+Nnbr8XFp7+o PmSZuV0uvea0djhOfySNg== X-UI-Out-Filterresults: notjunk:1;V03:K0:Kl1RwPLCH/I=:KXkkUHUWcJNE+Zj+FvkUDy lq4gy+LPzLV4vO/VF/UNZkPBMgyAsibbayiz8StjgmYw/xpRYuo7T5Mre1aZuEiFKa1ws6BLG BNRetjVlGp0A7rFTNnXb1oK9p4hSCm+LDjijyKh/HPCiBtb4S3Du0kxp3ybFiagRR7sERuGaf iQgHBfD5OfMtywjm2am/4lbFrbdovyejUES2PFJUnCPAvHBpP2LVqmzm+VxLCWbxbR70w5cAx 7VqfoglO46MjJQOUL+QM+QGd2JZ/dzUdG6UNilR+gLTXKDxWfFC7x7fU+c72j73lDJHdXEKKK LpC1XsWFT6ps95062/XNY61RxuE7mXL3ejqzq3LpnG6zTKFdwgyKjG/E5e7SywJ9W8Zk4rdXb 8cOAbD7MG0FZnznKxFn017bu6jTmijiFhiV+p9tkEM4QiTpgaiLvAC0L69Fg/B044g9L5YXSi RHNJ/eQav1lIc0nkQVMN3b+tZDGM6aSAZ5EDss5uAcfdYQ4HxvXlFgIk7BDgDu7BE+XRRZVBl hinRidWVW0Ta43kh96EkUmxLMHh+nFmSQIW9A1hyhw/U2ApQ9xPHk0mL5e+mgaIBVL8jXL5Td DLcHnQhMXBeiruqnDkJ8AWJyKJnewrWi2z82AzA9TmB+0/yfuFGQlFkalILlvZIaYstMlkyyJ zlGrDcU5f4ULLz+RB1UP7Lnk1CGz35oWYbd1dSzpODVaCfyhwUgdmSTq98o0Gjl++ZoFnDbr9 sn/UpbstaVaGtqY3MT5rcNwNpEPHfxTomhxbPRvl8aCynYrIycyJbUGqHHdJ06fS74LMhZ0yv heraOad92yYVvVr7wCN7e4Eels4Yskg60gN1VbqHdvpAKa8JB92rpjHPRDsz7r37PLemAKMyR zgtxUZfHx5fQblgi4cKj0F2EWNPEdnh/sizEhDZzWk5ZRSQbQfZ4VruDDHyA1Rcp3h2gs4a6h rdQ9jMf9ra1dIO9xhzSx1E6l5Xd67VVQ= Received-SPF: pass client-ip=212.227.17.22; envelope-from=xypron.glpk@gmx.de; helo=mout.gmx.net X-Spam_score_int: -27 X-Spam_score: -2.8 X-Spam_bar: -- X-Spam_report: (-2.8 / 5.0 requ) BAYES_00=-1.9, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, FREEMAIL_FROM=0.001, NICE_REPLY_A=-0.211, RCVD_IN_DNSWL_LOW=-0.7, RCVD_IN_MSPIKE_H2=-0.001, SPF_HELO_NONE=0.001, SPF_PASS=-0.001 autolearn=ham autolearn_force=no X-Spam_action: no action X-BeenThere: grub-devel@gnu.org X-Mailman-Version: 2.1.23 Precedence: list List-Id: The development of GNU GRUB List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Thu, 11 Feb 2021 08:52:00 -0000 On 11.02.21 08:36, Michael Lawnick wrote: > > Hi, > > seven days of silence. In the end no interest for extending EFI support? > > KR > Michael > > Am 05.02.2021 um 09:58 schrieb Michael Lawnick: >> Add EFI SPI NOR driver >> >> Use UEFI interface for accessing SPI NOR flashes. >> If supported the implementation of UEFI boot software abstracts >> away all those ugly H/W details like SPI controller or protocol. >> Provided functions: >> grub_efi_spi_nor_ >> =C2=A0=C2=A0=C2=A0=C2=A0init >> =C2=A0=C2=A0=C2=A0=C2=A0erase >> =C2=A0=C2=A0=C2=A0=C2=A0write >> =C2=A0=C2=A0=C2=A0=C2=A0read >> =C2=A0=C2=A0=C2=A0=C2=A0flash_size >> =C2=A0=C2=A0=C2=A0=C2=A0flash_id >> =C2=A0=C2=A0=C2=A0=C2=A0erase_block_size >> >> This driver might be used for further abstraction to a common >> (SPI) flash interface. >> A commit message should describe what the patch is good for. What is the use case for GRUB accessing SPI? In your second patch you introduce a command to write and erase the SPI flash. Hopefully the firmware has disabled writes. GRUB writing to SPI would mean that a user program could introduce malware into the firmware by adding said command to grub.cfg. This would be a gross security issue. Hopefully the firmware has locked the SPI flash before entering GRUB. SPI flash updates should be effected via signed UEFI update capsules and not via GRUB. >> Signed-off-by: Michael Lawnick >> --- >> [Patch v2 1/2] : fix flaw in EFI header, wrong sequence of methods. >> --- >> diff --git a/grub-core/Makefile.core.def b/grub-core/Makefile.core.def >> index 68b9e9f68..4d775e5f6 100644 >> --- a/grub-core/Makefile.core.def >> +++ b/grub-core/Makefile.core.def >> @@ -446,7 +446,7 @@ image =3D { >> =C2=A0=C2=A0=C2=A0=C2=A0 i386_pc =3D boot/i386/pc/boot.S; >> >> =C2=A0=C2=A0=C2=A0=C2=A0 cppflags =3D '-DHYBRID_BOOT=3D1'; >> - >> + >> =C2=A0=C2=A0=C2=A0=C2=A0 i386_pc_ldflags =3D '$(TARGET_IMG_LDFLAGS)'; >> =C2=A0=C2=A0=C2=A0=C2=A0 i386_pc_ldflags =3D '$(TARGET_IMG_BASE_LDOPT),= 0x7C00'; >> >> @@ -656,6 +656,12 @@ module =3D { >> =C2=A0=C2=A0=C2=A0=C2=A0 enable =3D i386_multiboot; >> =C2=A0=C2=A0 }; >> >> +module =3D { >> +=C2=A0 name =3D efi_spi_nor; >> +=C2=A0 common =3D bus/spi/efi_spi_nor.c; >> +=C2=A0 enable =3D efi; >> +}; >> + >> =C2=A0=C2=A0 module =3D { >> =C2=A0=C2=A0=C2=A0=C2=A0 name =3D nativedisk; >> =C2=A0=C2=A0=C2=A0=C2=A0 common =3D commands/nativedisk.c; >> diff --git a/grub-core/bus/spi/efi_spi_nor.c >> b/grub-core/bus/spi/efi_spi_nor.c >> new file mode 100644 >> index 000000000..0e073b436 >> --- /dev/null >> +++ b/grub-core/bus/spi/efi_spi_nor.c >> @@ -0,0 +1,298 @@ >> +/*=C2=A0 efi_spi_nor.c=C2=A0 - Give access to SPI NOR flash through UE= FI >> interface. >> + *=C2=A0 Copyright 2021 Nokia >> + *=C2=A0 Licensed under the GNU General Public License v3.0 only >> + *=C2=A0 SPDX-License-Identifier: GPL-3.0-only >> + * >> + *=C2=A0 GRUB=C2=A0 --=C2=A0 GRand Unified Bootloader >> + *=C2=A0 Copyright (C) 2008=C2=A0 Free Software Foundation, Inc. The FSF wrote part of this code in 2008? >> + * >> + *=C2=A0 GRUB is free software: you can redistribute it and/or modify >> + *=C2=A0 it under the terms of the GNU General Public License as publi= shed by >> + *=C2=A0 the Free Software Foundation, either version 3 of the License= , or >> + *=C2=A0 (at your option) any later version. >> + * >> + *=C2=A0 GRUB is distributed in the hope that it will be useful, >> + *=C2=A0 but WITHOUT ANY WARRANTY; without even the implied warranty o= f >> + *=C2=A0 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.=C2=A0 Se= e the >> + *=C2=A0 GNU General Public License for more details. >> + * >> + *=C2=A0 You should have received a copy of the GNU General Public Lic= ense >> + *=C2=A0 along with GRUB.=C2=A0 If not, see . >> + */ >> +#include >> +#include >> +#include >> +#include >> +#include >> +#include >> +#include >> + >> +GRUB_MOD_LICENSE ("GPLv3+"); >> + >> +#define EFI_SPI_NOR_FLASH_PROTOCOL_GUID \ >> +=C2=A0=C2=A0=C2=A0 { 0xb57ec3fe, 0xf833, 0x4ba6, \ >> +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 {0x85, 0x78, 0x2a, 0x7d, 0x= 6a, 0x87, 0x44, 0x4b} \ >> +=C2=A0=C2=A0=C2=A0 } This protocol is not defined in the UEFI spec 2.8B. It is defined in the Platform Initialization (PI) Specification, Volume 1, Pre-EFI Initialization Core Interface. So it seems it is not meant to be consumed by UEFI applications. U-Boot adheres to the UEFI spec but has no PI phase. So don't expect the protocol there. Best regards Heinrich >> + >> +#define EFI_FLASHID_LEN 3 >> + >> +struct efi_spi_nor_flash_protocol { >> +=C2=A0=C2=A0=C2=A0 struct spi_nor=C2=A0=C2=A0=C2=A0 *spi_peripheral; >> +=C2=A0=C2=A0=C2=A0 grub_efi_uint32_t=C2=A0=C2=A0=C2=A0 flash_size; >> +=C2=A0=C2=A0=C2=A0 grub_efi_uint8_t=C2=A0=C2=A0=C2=A0 device_id[EFI_FL= ASHID_LEN]; >> +=C2=A0=C2=A0=C2=A0 grub_efi_uint32_t=C2=A0=C2=A0=C2=A0 erase_block_siz= e; >> + >> +=C2=A0=C2=A0=C2=A0 grub_efi_status_t (* get_flash_id)(struct efi_spi_n= or_flash_protocol >> *this, >> +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2= =A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2= =A0 grub_uint8_t *buffer); >> +=C2=A0=C2=A0=C2=A0 grub_efi_status_t (* read_data)(struct efi_spi_nor_= flash_protocol >> *this, >> +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2= =A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 grub_uint32_t of= fset, grub_uint32_t len, >> grub_uint8_t *data); >> +=C2=A0=C2=A0=C2=A0 grub_efi_status_t (* lf_read_data)(struct efi_spi_n= or_flash_protocol >> *this, >> +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2= =A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2= =A0 grub_uint32_t offset, grub_uint32_t len, >> grub_uint8_t *data); >> +=C2=A0=C2=A0=C2=A0 grub_efi_status_t (* read_status)(struct >> efi_spi_nor_flash_protocol *this, >> +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2= =A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 grub= _uint32_t num_bytes, grub_uint8_t *status); >> +=C2=A0=C2=A0=C2=A0 grub_efi_status_t (* write_status)(struct efi_spi_n= or_flash_protocol >> *this, >> +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2= =A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2= =A0 grub_uint32_t num_bytes, grub_uint8_t *status); >> +=C2=A0=C2=A0=C2=A0 grub_efi_status_t (* write_data)(struct >> efi_spi_nor_flash_protocol *this, >> +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2= =A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 grub_uint3= 2_t offset, grub_uint32_t len, >> grub_uint8_t *data); >> +=C2=A0=C2=A0=C2=A0 grub_efi_status_t (* erase_blocks)(struct efi_spi_n= or_flash_protocol >> *this, >> +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2= =A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2= =A0 grub_uint32_t offset, grub_uint32_t blk_count); >> +}; >> + >> +/* grub_efi_spi_nor_init - initialize access to SPI NOR flash device >> + * >> + * Search pool of SPI NOR flash devices known to underlying EFI >> bootware. >> + * Use and to filter out devices. >> + * >> + * IN: flash_id=C2=A0=C2=A0=C2=A0=C2=A0 - optional, pointer to max 3 b= ytes >> (EFI_FLASHID_LEN) to match against >> + *=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0= =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 SPI flash JEDEC ID, use N= ULL if no filtering. >> + * IN: num_id_bytes - number of bytes in flash_id. Maximum 3 bytes >> + *=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0= =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 are used for comparison. >> + * IN: instance=C2=A0=C2=A0=C2=A0=C2=A0 - number of device occurances = to skip >> + * >> + * returns : pointer to flash device or NULL on failure >> + */ >> +void * >> +grub_efi_spi_nor_init(grub_uint8_t *flash_id, grub_uint32_t >> num_id_bytes, grub_uint32_t instance) >> +{ >> +=C2=A0=C2=A0=C2=A0 grub_efi_guid_t efi_guid_spi_nor_flash_protocol =3D >> EFI_SPI_NOR_FLASH_PROTOCOL_GUID; >> +=C2=A0=C2=A0=C2=A0 grub_efi_status_t ret; >> +=C2=A0=C2=A0=C2=A0 grub_efi_uintn_t num_handles; >> +=C2=A0=C2=A0=C2=A0 grub_efi_handle_t *handles; >> +=C2=A0=C2=A0=C2=A0 grub_uint8_t found_id[EFI_FLASHID_LEN]; >> +=C2=A0=C2=A0=C2=A0 grub_uint32_t idx, match_cnt=3D0; >> +=C2=A0=C2=A0=C2=A0 struct efi_spi_nor_flash_protocol *spi_nor; >> + >> +=C2=A0=C2=A0=C2=A0 handles =3D grub_efi_locate_handle(GRUB_EFI_BY_PROT= OCOL, >> +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2= =A0=C2=A0=C2=A0=C2=A0 &efi_guid_spi_nor_flash_protocol, 0, >> +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2= =A0=C2=A0=C2=A0=C2=A0 &num_handles); >> +=C2=A0=C2=A0=C2=A0 grub_boot_time("found %ld SPI NOR flash devices\n",= num_handles); >> + >> +=C2=A0=C2=A0=C2=A0 if ((num_handles =3D=3D 0) || (num_handles < instan= ce + 1)) >> +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 return NULL; >> + >> +=C2=A0=C2=A0=C2=A0 for (idx =3D 0; idx < num_handles; idx++) { >> +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 spi_nor =3D grub_efi_open_p= rotocol(handles[idx], >> +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2= =A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 &efi= _guid_spi_nor_flash_protocol, >> +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2= =A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 GRUB= _EFI_OPEN_PROTOCOL_GET_PROTOCOL); >> +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 if (! spi_nor) { >> +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 gru= b_error(GRUB_ERR_UNKNOWN_DEVICE, "Failed to open >> device protocol\n"); >> +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 gru= b_free(handles); >> +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 ret= urn NULL; >> +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 } >> + >> +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 ret =3D spi_nor->get_flash_= id(spi_nor, found_id); >> +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 if (ret !=3D GRUB_EFI_SUCCE= SS) { >> +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 gru= b_error(GRUB_ERR_READ_ERROR, "Failed to read >> flash_id\n"); >> +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 gru= b_free(handles); >> +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 ret= urn NULL; >> +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 } >> + >> +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 /* if caller requests filte= ring by id */ >> +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 if (flash_id !=3D NULL) { >> +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 gru= b_uint32_t id; >> + >> +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 if = (num_id_bytes > EFI_FLASHID_LEN) >> +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2= =A0=C2=A0=C2=A0=C2=A0 num_id_bytes =3D EFI_FLASHID_LEN; >> + >> +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 for= (id =3D 0; id < num_id_bytes; id++) >> +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2= =A0=C2=A0=C2=A0=C2=A0 if (flash_id[id] !=3D found_id[id]) >> +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2= =A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 break; >> + >> +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 if = (id !=3D num_id_bytes) >> +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2= =A0=C2=A0=C2=A0=C2=A0 continue; >> +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 } >> + >> +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 if (match_cnt < instance) { >> +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 mat= ch_cnt++; >> +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 con= tinue; >> +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 } >> + >> +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 grub_boot_time("Found flash= with ID 0x%02x 0x%02x 0x%02x\n", >> +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2= =A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 foun= d_id[0], found_id[1], found_id[2]); >> + >> +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 grub_free(handles); >> +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 return spi_nor; >> +=C2=A0=C2=A0=C2=A0 } >> + >> +=C2=A0=C2=A0=C2=A0 grub_free(handles); >> +=C2=A0=C2=A0=C2=A0 return NULL; >> +} >> + >> +/* grub_efi_spi_nor_flash_size - get memory size of SPI NOR flash devi= ce >> + * >> + * IN: efi_flash_dev - device identifier returned by >> grub_efi_spi_nor_init. >> + * >> + * returns : memory size of flash device or 0 on failure >> + */ >> +grub_uint32_t >> +grub_efi_spi_nor_flash_size(void *efi_flash_dev) >> +{ >> +=C2=A0=C2=A0=C2=A0 struct efi_spi_nor_flash_protocol *spi_nor =3D efi_= flash_dev; >> + >> +=C2=A0=C2=A0=C2=A0 if (spi_nor =3D=3D NULL) >> +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 return 0; >> + >> +=C2=A0=C2=A0=C2=A0 return spi_nor->flash_size; >> +} >> + >> +/* grub_efi_spi_nor_device_id - get three byte JEDEC ID of SPI NOR >> flash device >> + * >> + * IN: efi_flash_dev - device identifier returned by >> grub_efi_spi_nor_init. >> + * >> + * returns : three byte JEDEC ID as a uint32 or 0 on failure >> + */ >> +grub_uint32_t >> +grub_efi_spi_nor_device_id(void *efi_flash_dev) >> +{ >> +=C2=A0=C2=A0=C2=A0 struct efi_spi_nor_flash_protocol *spi_nor =3D efi_= flash_dev; >> +=C2=A0=C2=A0=C2=A0 grub_uint32_t devId =3D 0; >> +=C2=A0=C2=A0=C2=A0 grub_efi_status_t ret; >> +=C2=A0=C2=A0=C2=A0 grub_uint8_t device_id[3]; >> +=C2=A0=C2=A0=C2=A0 int i; >> + >> +=C2=A0=C2=A0=C2=A0 if (spi_nor =3D=3D NULL) >> +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 return 0; >> + >> +=C2=A0=C2=A0=C2=A0 ret =3D spi_nor->get_flash_id(spi_nor, device_id); >> +=C2=A0=C2=A0=C2=A0 if (ret !=3D GRUB_EFI_SUCCESS) >> +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 return 0; >> + >> +=C2=A0=C2=A0=C2=A0 for(i=3D0; i<3;i++) >> +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 devId =3D (devId<<8) + devi= ce_id[i]; >> + >> +=C2=A0=C2=A0=C2=A0 return devId; >> +} >> + >> +/* grub_efi_spi_nor_erase_block_size - get erase block size of SPI NOR >> flash device >> + * >> + * Parameters for calls to grub_efi_spi_nor_erase() need to be erase >> block size >> + * aligned. >> + * >> + * IN: efi_flash_dev - device identifier returned by >> grub_efi_spi_nor_init. >> + * >> + * returns : size of erase block of flash device or 0 on failure >> + */ >> +grub_uint32_t >> +grub_efi_spi_nor_erase_block_size(void *efi_flash_dev) >> +{ >> +=C2=A0=C2=A0=C2=A0 struct efi_spi_nor_flash_protocol *spi_nor =3D efi_= flash_dev; >> + >> +=C2=A0=C2=A0=C2=A0 if (spi_nor =3D=3D NULL) >> +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 return 0; >> + >> +=C2=A0=C2=A0=C2=A0 return spi_nor->erase_block_size; >> +} >> + >> +/* grub_efi_spi_nor_read - read from SPI NOR flash device >> + * >> + * IN:=C2=A0 efi_flash_dev - device identifier returned by >> grub_efi_spi_nor_init. >> + * OUT: buffer=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 - pointer to = an preallocated buffer of min. bytes >> size >> + * IN:=C2=A0 offset=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 - starti= ng point where to start to read from >> + * IN:=C2=A0 bytes=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 - n= umber of bytes to read from flash and write to >> buffer >> + * >> + * returns : GRUB_EFI_SUCCESS if all ok >> + *=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 GRUB_EF= I_INVALID_PARAMETER if an argument is bad >> + * >> + */ >> +grub_err_t >> +grub_efi_spi_nor_read(void *efi_flash_dev, grub_uint8_t *buffer, >> grub_uint32_t offset, grub_uint32_t bytes) >> +{ >> +=C2=A0=C2=A0=C2=A0 struct efi_spi_nor_flash_protocol *spi_nor =3D efi_= flash_dev; >> +=C2=A0=C2=A0=C2=A0 grub_efi_status_t ret; >> + >> +=C2=A0=C2=A0=C2=A0 if (spi_nor =3D=3D NULL || buffer =3D=3D NULL) >> +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 return GRUB_ERR_BAD_ARGUMEN= T; >> + >> +=C2=A0=C2=A0=C2=A0 ret =3D (spi_nor->read_data(spi_nor, offset, bytes,= buffer)); >> +=C2=A0=C2=A0=C2=A0 if (ret !=3D GRUB_EFI_SUCCESS) >> +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 return grub_error(GRUB_ERR_= READ_ERROR, "Failed to read data >> @0x%x\n", >> offset); >> + >> +=C2=A0=C2=A0=C2=A0 return GRUB_ERR_NONE; >> +} >> + >> +/* grub_efi_spi_nor_write - write to SPI NOR flash device >> + * >> + * IN: efi_flash_dev - device identifier returned by >> grub_efi_spi_nor_init. >> + * IN: buffer=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 - pointer to b= uffer containig min. bytes size data >> to write >> + * IN: offset=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 - starting poi= nt where to start to write to >> + * IN: bytes=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 - number = of bytes to write to buffer >> + * >> + * returns : GRUB_EFI_SUCCESS if all ok >> + *=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 GRUB_EF= I_INVALID_PARAMETER if an argument is bad >> + * >> + */ >> +grub_err_t >> +grub_efi_spi_nor_write(void *efi_flash_dev, grub_uint8_t *buffer, >> grub_uint32_t offset, grub_uint32_t bytes) >> +{ >> +=C2=A0=C2=A0=C2=A0 struct efi_spi_nor_flash_protocol *spi_nor =3D efi_= flash_dev; >> +=C2=A0=C2=A0=C2=A0 grub_efi_status_t ret; >> + >> +=C2=A0=C2=A0=C2=A0 if (spi_nor =3D=3D NULL || buffer =3D=3D NULL) >> +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 return GRUB_ERR_BAD_ARGUMEN= T; >> + >> +=C2=A0=C2=A0=C2=A0 ret =3D (spi_nor->write_data(spi_nor, offset, bytes= , buffer)); >> +=C2=A0=C2=A0=C2=A0 if (ret !=3D GRUB_EFI_SUCCESS) >> +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 return grub_error(GRUB_ERR_= WRITE_ERROR, "Failed to write data >> @0x%x\n", offset); >> + >> +=C2=A0=C2=A0=C2=A0 return GRUB_ERR_NONE; >> +} >> + >> +/* grub_efi_spi_nor_erase - erase sectors on SPI NOR flash device >> + * >> + * Parameters offset and bytes need to be erase sector aligned, i.e. >> + * multiples of the size returned by function >> grub_efi_spi_nor_erase_block_size() >> + * >> + * IN: efi_flash_dev - device identifier returned by >> grub_efi_spi_nor_init. >> + * IN: offset=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 - offset of fi= rst sector to erase >> + * IN: bytes=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 - length = of region to erase >> + * >> + * returns : GRUB_EFI_SUCCESS if all ok >> + *=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 GRUB_EF= I_INVALID_PARAMETER if an argument is bad >> + * >> + */ >> +grub_err_t >> +grub_efi_spi_nor_erase(void *efi_flash_dev, grub_uint32_t offset, >> grub_uint32_t bytes) >> +{ >> +=C2=A0=C2=A0=C2=A0 struct efi_spi_nor_flash_protocol *spi_nor =3D efi_= flash_dev; >> +=C2=A0=C2=A0=C2=A0 grub_efi_status_t ret; >> +=C2=A0=C2=A0=C2=A0 grub_uint32_t sect_sz; >> +=C2=A0=C2=A0=C2=A0 grub_uint32_t sect_mask; >> + >> +=C2=A0=C2=A0=C2=A0 if (spi_nor =3D=3D NULL || bytes =3D=3D 0) >> +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 return GRUB_ERR_BAD_ARGUMEN= T; >> + >> +=C2=A0=C2=A0=C2=A0 sect_sz =3D grub_efi_spi_nor_erase_block_size(spi_n= or); >> +=C2=A0=C2=A0=C2=A0 sect_mask =3D sect_sz - 1; >> +=C2=A0=C2=A0=C2=A0 if ((offset & sect_mask) !=3D 0) >> +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 return grub_error(GRUB_ERR_= BAD_ARGUMENT, "SPI NOR erase >> offset not at >> sector boundary"); >> + >> +=C2=A0=C2=A0=C2=A0 if (((offset + bytes) & sect_mask) !=3D 0) >> +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 return grub_error(GRUB_ERR_= BAD_ARGUMENT, "SPI NOR erase end >> not at >> sector boundary"); >> + >> +=C2=A0=C2=A0=C2=A0 ret =3D spi_nor->erase_blocks(spi_nor, offset, (byt= es-1) / sect_sz >> + 1); >> + >> +=C2=A0=C2=A0=C2=A0 if (ret !=3D GRUB_EFI_SUCCESS) >> +=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 return grub_error(GRUB_ERR_= WRITE_ERROR, "SPI NOR erase operation >> failed"); >> + >> +=C2=A0=C2=A0=C2=A0 return GRUB_ERR_NONE; >> +} >> diff --git a/include/grub/efi/efi_spi_nor.h >> b/include/grub/efi/efi_spi_nor.h >> new file mode 100644 >> index 000000000..d09f0c9b7 >> --- /dev/null >> +++ b/include/grub/efi/efi_spi_nor.h >> @@ -0,0 +1,37 @@ >> +/*=C2=A0 efi_spi_nor.h=C2=A0 - Give access to SPI NOR flash through UE= FI >> interface. >> + *=C2=A0 Copyright 2021 Nokia >> + *=C2=A0 Licensed under the GNU General Public License v3.0 only >> + *=C2=A0 SPDX-License-Identifier: GPL-3.0-only >> + * >> + *=C2=A0 GRUB=C2=A0 --=C2=A0 GRand Unified Bootloader >> + *=C2=A0 Copyright (C) 2008=C2=A0 Free Software Foundation, Inc. >> + * >> + *=C2=A0 GRUB is free software: you can redistribute it and/or modify >> + *=C2=A0 it under the terms of the GNU General Public License as publi= shed by >> + *=C2=A0 the Free Software Foundation, either version 3 of the License= , or >> + *=C2=A0 (at your option) any later version. >> + * >> + *=C2=A0 GRUB is distributed in the hope that it will be useful, >> + *=C2=A0 but WITHOUT ANY WARRANTY; without even the implied warranty o= f >> + *=C2=A0 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.=C2=A0 Se= e the >> + *=C2=A0 GNU General Public License for more details. >> + * >> + *=C2=A0 You should have received a copy of the GNU General Public Lic= ense >> + *=C2=A0 along with GRUB.=C2=A0 If not, see . >> + */ >> +#ifndef GRUB_EFI_SPI_NOR_HEADER >> +#define GRUB_EFI_SPI_NOR_HEADER >> + >> +#include >> + >> +void *grub_efi_spi_nor_init(grub_uint8_t *flash_id, grub_uint32_t >> num_id_bytes, grub_uint32_t instance); >> + >> +grub_uint32_t grub_efi_spi_nor_flash_size(void *efi_flash_dev); >> +grub_uint32_t grub_efi_spi_nor_device_id(void *efi_flash_dev); >> +grub_uint32_t grub_efi_spi_nor_erase_block_size(void *efi_flash_dev); >> + >> +grub_err_t grub_efi_spi_nor_read(void *efi_flash_dev, grub_uint8_t >> *buffer, grub_uint32_t offset, grub_uint32_t bytes); >> +grub_err_t grub_efi_spi_nor_write(void *efi_flash_dev, grub_uint8_t >> *buffer, grub_uint32_t offset, grub_uint32_t bytes); >> +grub_err_t grub_efi_spi_nor_erase(void *efi_flash_dev, grub_uint32_t >> offset, grub_uint32_t bytes); >> + >> +#endif /*GRUB_EFISPINOR*/ >> >> _______________________________________________ >> Grub-devel mailing list >> Grub-devel@gnu.org >> https://lists.gnu.org/mailman/listinfo/grub-devel >> >