From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from list by lists.gnu.org with archive (Exim 4.90_1) id 1lA6Ww-0003L3-UT for mharc-grub-devel@gnu.org; Thu, 11 Feb 2021 02:36:50 -0500 Received: from eggs.gnu.org ([2001:470:142:3::10]:53898) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1lA6Wv-0003KY-22 for grub-devel@gnu.org; Thu, 11 Feb 2021 02:36:49 -0500 Received: from mout.gmx.net ([212.227.15.19]:40205) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1lA6Wr-0006Sn-UD for grub-devel@gnu.org; Thu, 11 Feb 2021 02:36:48 -0500 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=gmx.net; s=badeba3b8450; t=1613028988; bh=oEv+fWqogFnhqsVUqRafJDDUmzVzRDhG/DyhWmQeXeM=; h=X-UI-Sender-Class:Subject:From:To:Reply-To:References:Cc:Date: In-Reply-To; b=WMwts3EvW9sADYv+R/mQieI80JZeOAsPHY7wX7M4PNfjqHaTG92jPiVHh99CmruSW /KkG6MUi48j8glFCPYWj4QJBDdKgeN7UrICaVfoJtn90YKzoNAirR4APqP2ZyMIB7J wj+zQDb/qVTjjpo3LPS0EanrX2gzpWZ0OiL63gP8= X-UI-Sender-Class: 01bb95c1-4bf8-414a-932a-4f6e2808ef9c Received: from [172.30.9.9] ([131.228.32.169]) by mail.gmx.net (mrgmx005 [212.227.17.190]) with ESMTPSA (Nemesis) id 1MQMuR-1lWICg3v6H-00MHXB; Thu, 11 Feb 2021 08:36:28 +0100 Subject: Re: [PATCH v2 1/2] efi: SPI NOR flash support From: Michael Lawnick To: The development of GNU GRUB Reply-To: The development of GNU GRUB References: Cc: Paul Menzel , xypron.glpk@gmx.de Message-ID: <521ca300-6d1e-94ed-c87d-f4005a1f7870@gmx.de> Date: Thu, 11 Feb 2021 08:36:28 +0100 User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:78.0) Gecko/20100101 Thunderbird/78.7.1 MIME-Version: 1.0 In-Reply-To: Content-Type: text/plain; charset=utf-8; format=flowed Content-Language: en-US Content-Transfer-Encoding: quoted-printable X-Provags-ID: V03:K1:VX97NnlEwwVtXgbBL0LBOqa2GPd2823JifNaC385RpGNVZmcUPA e08Ct2MA7Td+z8rMum0mFwL7vlH1VnMygullXOh6XouOdJ0lU1Q42sDKzonucy3yf0z9C+2 p4ORpzcRY9UjKh0vXbhp85BABItS8Q3qb5gAirmWuVdoQpqsPZgwKlpCsQlQ/D2+kHzkpd8 xEuMKz1zYdMyJFXvWGeUQ== X-UI-Out-Filterresults: notjunk:1;V03:K0:6GdWXQtQGic=:kXkdLehLpMz0Nfcq6B1iyV saaP8FREfo4YUIsMOqFC7hxI5lZcNMAYsVA91schok4lnmQn8cFseZZfprLrTox2EfGBFA+ag HSLN2Zy17/4gnxU0lWNJgsGoOJ22ok7FQsmOVhC9YNY64A8NwoWUs5kOpGEyfW57G+pcGh6pK ZOGOng5qyISCE4VQjyhIeF4BgR8kyf26MG5sRrKgXhY+3H8t0TDTYu11UHJ6QZ80mlDb2GSn6 6SMYla959qyngF2hhVgbO+AFjKODwQoi1lT2ZiY8iYTO3/q5PbqudY9Tygq1efdqHeR7g7jET P9whgUdueZLrZrLEh4ZB4HbpvDz6CdFiVi0GqFjo/ORM74b58xiVgSKYSH4cooz5E7XCGKq83 +yjeqtQunT+CMFUO5cuLsz5rh+x4m0NzI7L5IprjT5TG3UMxs95/w2MrwF0l9Q+OgEB7LPyUA Uom72qBVPj/DvdpCjB2u/cxo5kBLfo987CJIg/ERhbCqnaRu3cTdcYpk+xO27gkbCLt03e7hU 1DFruyFFhZtkaVv589eXq/+4HmIFUU3f8ZSHl8MwFNRqY+ZYGmKmipQkvDQxzA2/YSWD8ttvK TNUdtKPC9jRjRdcQKAxvwxiWJjhbWdYbxgqLk77+ttqz1xXPYGUOqPQP81hhaWgtJ9VpyzXnU sKxVeRaUVlF2u0zrWUOkwpgiYSxB0NSbqIZdccdegUet+PLWC5WWuJErMsNIprMK8Q0CotmNj DM6M4iO5soqSrH6GKVmquJXgbIbh/c/mrSSHeyUm6neWKpbi5ozaJdQF1xuz6YQtWZ6ytf2AO dFwc/C9k0RJoPFPWasukao61cLBvLfhSMZ4WMPtowKA+n6aiTpyic9C17j1yOE5wizbxzmAWn 7DDdC87yEf+9fmTjnhKw== Received-SPF: pass client-ip=212.227.15.19; envelope-from=ml.lawnick@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_H3=0.001, RCVD_IN_MSPIKE_WL=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 07:36:49 -0000 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_ > init > erase > write > read > flash_size > flash_id > erase_block_size > > This driver might be used for further abstraction to a common > (SPI) flash interface. > > 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 { > i386_pc =3D boot/i386/pc/boot.S; > > cppflags =3D '-DHYBRID_BOOT=3D1'; > - > + > i386_pc_ldflags =3D '$(TARGET_IMG_LDFLAGS)'; > i386_pc_ldflags =3D '$(TARGET_IMG_BASE_LDOPT),0x7C00'; > > @@ -656,6 +656,12 @@ module =3D { > enable =3D i386_multiboot; > }; > > +module =3D { > + name =3D efi_spi_nor; > + common =3D bus/spi/efi_spi_nor.c; > + enable =3D efi; > +}; > + > module =3D { > name =3D nativedisk; > 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 @@ > +/* efi_spi_nor.c - Give access to SPI NOR flash through UEFI interfac= e. > + * Copyright 2021 Nokia > + * Licensed under the GNU General Public License v3.0 only > + * SPDX-License-Identifier: GPL-3.0-only > + * > + * GRUB -- GRand Unified Bootloader > + * Copyright (C) 2008 Free Software Foundation, Inc. > + * > + * GRUB is free software: you can redistribute it and/or modify > + * it under the terms of the GNU General Public License as published b= y > + * the Free Software Foundation, either version 3 of the License, or > + * (at your option) any later version. > + * > + * GRUB is distributed in the hope that it will be useful, > + * but WITHOUT ANY WARRANTY; without even the implied warranty of > + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the > + * GNU General Public License for more details. > + * > + * You should have received a copy of the GNU General Public License > + * along with GRUB. If not, see . > + */ > +#include > +#include > +#include > +#include > +#include > +#include > +#include > + > +GRUB_MOD_LICENSE ("GPLv3+"); > + > +#define EFI_SPI_NOR_FLASH_PROTOCOL_GUID \ > + { 0xb57ec3fe, 0xf833, 0x4ba6, \ > + {0x85, 0x78, 0x2a, 0x7d, 0x6a, 0x87, 0x44, 0x4b} \ > + } > + > +#define EFI_FLASHID_LEN 3 > + > +struct efi_spi_nor_flash_protocol { > + struct spi_nor *spi_peripheral; > + grub_efi_uint32_t flash_size; > + grub_efi_uint8_t device_id[EFI_FLASHID_LEN]; > + grub_efi_uint32_t erase_block_size; > + > + grub_efi_status_t (* get_flash_id)(struct efi_spi_nor_flash_protocol > *this, > + grub_uint8_t *buffer); > + grub_efi_status_t (* read_data)(struct efi_spi_nor_flash_protocol *thi= s, > + grub_uint32_t offset, grub_uint32_t len, grub_uint8_t *data); > + grub_efi_status_t (* lf_read_data)(struct efi_spi_nor_flash_protocol > *this, > + grub_uint32_t offset, grub_uint32_t len, grub_uint8_t *data); > + grub_efi_status_t (* read_status)(struct efi_spi_nor_flash_protocol *t= his, > + grub_uint32_t num_bytes, grub_uint8_t *status); > + grub_efi_status_t (* write_status)(struct efi_spi_nor_flash_protocol > *this, > + grub_uint32_t num_bytes, grub_uint8_t *status); > + grub_efi_status_t (* write_data)(struct efi_spi_nor_flash_protocol *th= is, > + grub_uint32_t offset, grub_uint32_t len, grub_uint8_t *data); > + grub_efi_status_t (* erase_blocks)(struct efi_spi_nor_flash_protocol > *this, > + 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 bootwar= e. > + * Use and to filter out devices. > + * > + * IN: flash_id - optional, pointer to max 3 bytes > (EFI_FLASHID_LEN) to match against > + * SPI flash JEDEC ID, use NULL if no filtering. > + * IN: num_id_bytes - number of bytes in flash_id. Maximum 3 bytes > + * are used for comparison. > + * IN: instance - 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) > +{ > + grub_efi_guid_t efi_guid_spi_nor_flash_protocol =3D > EFI_SPI_NOR_FLASH_PROTOCOL_GUID; > + grub_efi_status_t ret; > + grub_efi_uintn_t num_handles; > + grub_efi_handle_t *handles; > + grub_uint8_t found_id[EFI_FLASHID_LEN]; > + grub_uint32_t idx, match_cnt=3D0; > + struct efi_spi_nor_flash_protocol *spi_nor; > + > + handles =3D grub_efi_locate_handle(GRUB_EFI_BY_PROTOCOL, > + &efi_guid_spi_nor_flash_protocol, 0, > + &num_handles); > + grub_boot_time("found %ld SPI NOR flash devices\n", num_handles); > + > + if ((num_handles =3D=3D 0) || (num_handles < instance + 1)) > + return NULL; > + > + for (idx =3D 0; idx < num_handles; idx++) { > + spi_nor =3D grub_efi_open_protocol(handles[idx], > + &efi_guid_spi_nor_flash_protocol, > + GRUB_EFI_OPEN_PROTOCOL_GET_PROTOCOL); > + if (! spi_nor) { > + grub_error(GRUB_ERR_UNKNOWN_DEVICE, "Failed to open device protocol\= n"); > + grub_free(handles); > + return NULL; > + } > + > + ret =3D spi_nor->get_flash_id(spi_nor, found_id); > + if (ret !=3D GRUB_EFI_SUCCESS) { > + grub_error(GRUB_ERR_READ_ERROR, "Failed to read flash_id\n"); > + grub_free(handles); > + return NULL; > + } > + > + /* if caller requests filtering by id */ > + if (flash_id !=3D NULL) { > + grub_uint32_t id; > + > + if (num_id_bytes > EFI_FLASHID_LEN) > + num_id_bytes =3D EFI_FLASHID_LEN; > + > + for (id =3D 0; id < num_id_bytes; id++) > + if (flash_id[id] !=3D found_id[id]) > + break; > + > + if (id !=3D num_id_bytes) > + continue; > + } > + > + if (match_cnt < instance) { > + match_cnt++; > + continue; > + } > + > + grub_boot_time("Found flash with ID 0x%02x 0x%02x 0x%02x\n", > + found_id[0], found_id[1], found_id[2]); > + > + grub_free(handles); > + return spi_nor; > + } > + > + grub_free(handles); > + return NULL; > +} > + > +/* grub_efi_spi_nor_flash_size - get memory size of SPI NOR flash devic= e > + * > + * IN: efi_flash_dev - device identifier returned by grub_efi_spi_nor_i= nit. > + * > + * returns : memory size of flash device or 0 on failure > + */ > +grub_uint32_t > +grub_efi_spi_nor_flash_size(void *efi_flash_dev) > +{ > + struct efi_spi_nor_flash_protocol *spi_nor =3D efi_flash_dev; > + > + if (spi_nor =3D=3D NULL) > + return 0; > + > + 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_i= nit. > + * > + * 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) > +{ > + struct efi_spi_nor_flash_protocol *spi_nor =3D efi_flash_dev; > + grub_uint32_t devId =3D 0; > + grub_efi_status_t ret; > + grub_uint8_t device_id[3]; > + int i; > + > + if (spi_nor =3D=3D NULL) > + return 0; > + > + ret =3D spi_nor->get_flash_id(spi_nor, device_id); > + if (ret !=3D GRUB_EFI_SUCCESS) > + return 0; > + > + for(i=3D0; i<3;i++) > + devId =3D (devId<<8) + device_id[i]; > + > + 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_i= nit. > + * > + * 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) > +{ > + struct efi_spi_nor_flash_protocol *spi_nor =3D efi_flash_dev; > + > + if (spi_nor =3D=3D NULL) > + return 0; > + > + return spi_nor->erase_block_size; > +} > + > +/* grub_efi_spi_nor_read - read from SPI NOR flash device > + * > + * IN: efi_flash_dev - device identifier returned by > grub_efi_spi_nor_init. > + * OUT: buffer - pointer to an preallocated buffer of min. bytes > size > + * IN: offset - starting point where to start to read from > + * IN: bytes - number of bytes to read from flash and write to > buffer > + * > + * returns : GRUB_EFI_SUCCESS if all ok > + * GRUB_EFI_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) > +{ > + struct efi_spi_nor_flash_protocol *spi_nor =3D efi_flash_dev; > + grub_efi_status_t ret; > + > + if (spi_nor =3D=3D NULL || buffer =3D=3D NULL) > + return GRUB_ERR_BAD_ARGUMENT; > + > + ret =3D (spi_nor->read_data(spi_nor, offset, bytes, buffer)); > + if (ret !=3D GRUB_EFI_SUCCESS) > + return grub_error(GRUB_ERR_READ_ERROR, "Failed to read data @0x%x\n", > offset); > + > + 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_i= nit. > + * IN: buffer - pointer to buffer containig min. bytes size data > to write > + * IN: offset - starting point where to start to write to > + * IN: bytes - number of bytes to write to buffer > + * > + * returns : GRUB_EFI_SUCCESS if all ok > + * GRUB_EFI_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) > +{ > + struct efi_spi_nor_flash_protocol *spi_nor =3D efi_flash_dev; > + grub_efi_status_t ret; > + > + if (spi_nor =3D=3D NULL || buffer =3D=3D NULL) > + return GRUB_ERR_BAD_ARGUMENT; > + > + ret =3D (spi_nor->write_data(spi_nor, offset, bytes, buffer)); > + if (ret !=3D GRUB_EFI_SUCCESS) > + return grub_error(GRUB_ERR_WRITE_ERROR, "Failed to write data > @0x%x\n", offset); > + > + 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_i= nit. > + * IN: offset - offset of first sector to erase > + * IN: bytes - length of region to erase > + * > + * returns : GRUB_EFI_SUCCESS if all ok > + * GRUB_EFI_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) > +{ > + struct efi_spi_nor_flash_protocol *spi_nor =3D efi_flash_dev; > + grub_efi_status_t ret; > + grub_uint32_t sect_sz; > + grub_uint32_t sect_mask; > + > + if (spi_nor =3D=3D NULL || bytes =3D=3D 0) > + return GRUB_ERR_BAD_ARGUMENT; > + > + sect_sz =3D grub_efi_spi_nor_erase_block_size(spi_nor); > + sect_mask =3D sect_sz - 1; > + if ((offset & sect_mask) !=3D 0) > + return grub_error(GRUB_ERR_BAD_ARGUMENT, "SPI NOR erase offset not at > sector boundary"); > + > + if (((offset + bytes) & sect_mask) !=3D 0) > + return grub_error(GRUB_ERR_BAD_ARGUMENT, "SPI NOR erase end not at > sector boundary"); > + > + ret =3D spi_nor->erase_blocks(spi_nor, offset, (bytes-1) / sect_sz + 1= ); > + > + if (ret !=3D GRUB_EFI_SUCCESS) > + return grub_error(GRUB_ERR_WRITE_ERROR, "SPI NOR erase operation > failed"); > + > + return GRUB_ERR_NONE; > +} > diff --git a/include/grub/efi/efi_spi_nor.h b/include/grub/efi/efi_spi_n= or.h > new file mode 100644 > index 000000000..d09f0c9b7 > --- /dev/null > +++ b/include/grub/efi/efi_spi_nor.h > @@ -0,0 +1,37 @@ > +/* efi_spi_nor.h - Give access to SPI NOR flash through UEFI interfac= e. > + * Copyright 2021 Nokia > + * Licensed under the GNU General Public License v3.0 only > + * SPDX-License-Identifier: GPL-3.0-only > + * > + * GRUB -- GRand Unified Bootloader > + * Copyright (C) 2008 Free Software Foundation, Inc. > + * > + * GRUB is free software: you can redistribute it and/or modify > + * it under the terms of the GNU General Public License as published b= y > + * the Free Software Foundation, either version 3 of the License, or > + * (at your option) any later version. > + * > + * GRUB is distributed in the hope that it will be useful, > + * but WITHOUT ANY WARRANTY; without even the implied warranty of > + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the > + * GNU General Public License for more details. > + * > + * You should have received a copy of the GNU General Public License > + * along with GRUB. 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 >