From patchwork Fri May 15 01:41:38 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Dmitry Osipenko X-Patchwork-Id: 1290789 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=vger.kernel.org (client-ip=23.128.96.18; helo=vger.kernel.org; envelope-from=linux-tegra-owner@vger.kernel.org; receiver=) Authentication-Results: ozlabs.org; dmarc=pass (p=none dis=none) header.from=gmail.com Authentication-Results: ozlabs.org; dkim=pass (2048-bit key; unprotected) header.d=gmail.com header.i=@gmail.com header.a=rsa-sha256 header.s=20161025 header.b=hpYWXz9c; dkim-atps=neutral Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by ozlabs.org (Postfix) with ESMTP id 49NWQH0vMxz9sTD for ; Fri, 15 May 2020 11:43:19 +1000 (AEST) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1728316AbgEOBmw (ORCPT ); Thu, 14 May 2020 21:42:52 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:55856 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1726170AbgEOBmu (ORCPT ); Thu, 14 May 2020 21:42:50 -0400 Received: from mail-lj1-x244.google.com (mail-lj1-x244.google.com [IPv6:2a00:1450:4864:20::244]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id C9070C061A0C; Thu, 14 May 2020 18:42:49 -0700 (PDT) Received: by mail-lj1-x244.google.com with SMTP id e25so475450ljg.5; Thu, 14 May 2020 18:42:49 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; bh=hY+h+hQNft22sbR2GRHdulgy1g8os6lzLdmN2sCZ1lE=; b=hpYWXz9cOLo7O2IXWeM/JpwktEaIYJmYkUm63rJSdzrIZjaGXcK4WfSKmzz7w8TNW4 pLM2wkRdRjyfJhO02BxNVSg52g1gi5peBx2hg0hoHOJIxiPMPHwvbfxGO44kMDv564jZ SBYLnd9x4lR3IzHMLryyc9FOq175xqOJrieCe4GmocyGfQuK1kfsYOrTxhKpO7Psy7Cj EXFL951nV0VHsMiKrX/ROuOHE4PWR2iiMhJ4wcwtF/M5fupE6nBLSyZjJstCwAvdk56G G9tIJDV6fp8jNeIUMWtBu5Pws0yi5zmKgfFz4WYizcsJohwQ2g5MwoGXCfp72gZv0dlA Ye0g== 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=hY+h+hQNft22sbR2GRHdulgy1g8os6lzLdmN2sCZ1lE=; b=cagLZ0b3Vt2JG+1O8Shbkjsy4XJ13WeLM5HzUwujYd8kyRoNxb6YUK7xPyp0hTdGam uMDWyP//KnMRQrTK+SMwJ4AXsnnnBDvKDBhUP6VV/3xbWuSnAP6IMHM81giVWNTD/xgu W7dpgpqM8KwmMgH7hgUS89/rtU+9K7VAen+5JF+iVWP5+JwJUQvv77CIPo5IrNMGnV1Q NOACXuORFkYQgmqxsG1C18gtEHdcUAaQaetIbTMvIPOL0Tp4vfeQ5YCADZ991QxnFKiu sQn3AHrT4gt/xWoLgWWAWTJ8FYb9MBWJ64wLhEb2ni/ZpRoKYkNXi3piTK+WrpyWUvdU Nl3g== X-Gm-Message-State: AOAM53174e49C9uFEbJRocms/5u3Ug/GM61z+jz98Ysx2fSFxxXKkHCA djwKetYyLB/Rz1+XwTLoNQI= X-Google-Smtp-Source: ABdhPJwXJTmffyGCIHEU0fLqa8XYSSYSNQU3NSvh1kPxhok4OLg+x9AfceTzW+o/4yurd0Tx+klhOA== X-Received: by 2002:a2e:731a:: with SMTP id o26mr652912ljc.189.1589506968312; Thu, 14 May 2020 18:42:48 -0700 (PDT) Received: from localhost.localdomain (ppp91-78-208-152.pppoe.mtu-net.ru. [91.78.208.152]) by smtp.gmail.com with ESMTPSA id i1sm309669lja.3.2020.05.14.18.42.46 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 14 May 2020 18:42:47 -0700 (PDT) From: Dmitry Osipenko To: Jens Axboe , Thierry Reding , Jonathan Hunter , =?utf-8?b?TWljaGHFgiBNaXJvc8WCYXc=?= , David Heidelberg , Peter Geis , Stephen Warren , Nicolas Chauvet , Ulf Hansson , Adrian Hunter , Billy Laws , =?utf-8?q?Nils_=C3=96stlund?= , Christoph Hellwig , Ard Biesheuvel , Davidlohr Bueso Cc: linux-tegra@vger.kernel.org, linux-block@vger.kernel.org, Andrey Danin , Gilles Grandou , Ryan Grachek , linux-mmc@vger.kernel.org, linux-kernel@vger.kernel.org, linux-efi Subject: [PATCH v4 1/6] mmc: core: Add raw_boot_mult field to mmc_ext_csd Date: Fri, 15 May 2020 04:41:38 +0300 Message-Id: <20200515014143.12984-2-digetx@gmail.com> X-Mailer: git-send-email 2.26.0 In-Reply-To: <20200515014143.12984-1-digetx@gmail.com> References: <20200515014143.12984-1-digetx@gmail.com> MIME-Version: 1.0 Sender: linux-tegra-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-tegra@vger.kernel.org In order to support parsing of NVIDIA Tegra Partition Table format, we need to know the BOOT_SIZE_MULT value of the Extended CSD register because NVIDIA's bootloader linearizes the boot0/boot1/main partitions into a single virtual space, and thus, all partition addresses are shifted by the size of boot0 + boot1 partitions. Signed-off-by: Dmitry Osipenko --- drivers/mmc/core/mmc.c | 2 ++ include/linux/mmc/card.h | 1 + 2 files changed, 3 insertions(+) diff --git a/drivers/mmc/core/mmc.c b/drivers/mmc/core/mmc.c index 4203303f946a..112edfb1eb1d 100644 --- a/drivers/mmc/core/mmc.c +++ b/drivers/mmc/core/mmc.c @@ -417,6 +417,8 @@ static int mmc_decode_ext_csd(struct mmc_card *card, u8 *ext_csd) ext_csd[EXT_CSD_ERASE_TIMEOUT_MULT]; card->ext_csd.raw_hc_erase_grp_size = ext_csd[EXT_CSD_HC_ERASE_GRP_SIZE]; + card->ext_csd.raw_boot_mult = + ext_csd[EXT_CSD_BOOT_MULT]; if (card->ext_csd.rev >= 3) { u8 sa_shift = ext_csd[EXT_CSD_S_A_TIMEOUT]; card->ext_csd.part_config = ext_csd[EXT_CSD_PART_CONFIG]; diff --git a/include/linux/mmc/card.h b/include/linux/mmc/card.h index 7d46411ffaa2..cd6b58b66010 100644 --- a/include/linux/mmc/card.h +++ b/include/linux/mmc/card.h @@ -109,6 +109,7 @@ struct mmc_ext_csd { u8 raw_hc_erase_gap_size; /* 221 */ u8 raw_erase_timeout_mult; /* 223 */ u8 raw_hc_erase_grp_size; /* 224 */ + u8 raw_boot_mult; /* 226 */ u8 raw_sec_trim_mult; /* 229 */ u8 raw_sec_erase_mult; /* 230 */ u8 raw_sec_feature_support;/* 231 */ From patchwork Fri May 15 01:41:39 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Dmitry Osipenko X-Patchwork-Id: 1290784 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=vger.kernel.org (client-ip=23.128.96.18; helo=vger.kernel.org; envelope-from=linux-tegra-owner@vger.kernel.org; receiver=) Authentication-Results: ozlabs.org; dmarc=pass (p=none dis=none) header.from=gmail.com Authentication-Results: ozlabs.org; dkim=pass (2048-bit key; unprotected) header.d=gmail.com header.i=@gmail.com header.a=rsa-sha256 header.s=20161025 header.b=HizLxqe9; dkim-atps=neutral Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by ozlabs.org (Postfix) with ESMTP id 49NWPq4Wxmz9sTS for ; Fri, 15 May 2020 11:42:55 +1000 (AEST) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1728370AbgEOBmx (ORCPT ); Thu, 14 May 2020 21:42:53 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:55858 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1728319AbgEOBmw (ORCPT ); Thu, 14 May 2020 21:42:52 -0400 Received: from mail-lf1-x141.google.com (mail-lf1-x141.google.com [IPv6:2a00:1450:4864:20::141]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 17A2AC05BD43; Thu, 14 May 2020 18:42:51 -0700 (PDT) Received: by mail-lf1-x141.google.com with SMTP id a9so436529lfb.8; Thu, 14 May 2020 18:42:51 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; bh=xOq5yyY/u+0O8ZudKc0fLqZJ0PgNfXdMDM0w1gmW1jw=; b=HizLxqe9cbA7I89vVR0kH8cDoiTOaqqkcABXr7Qc3JWYeOpKSfuAq84PQWKpHS6xTb pEkhH41ezKMGz9Bx06+q2arg8e0zvi4n0/tVr8QB7P5bL2ZtY/plVznDU6c75Wsb/iz3 DA1mrUnU5cYS5fzcx10E345AHgsjMpnDbpOIlxO12lTE21snp93spwXOZ47SMTdpcZRZ n1giWf19JCvOaZZ5o4dUW6zsLEwKari9r0a7yoTkKeiEJKHQYKRFaVGRaUlQpLo1K5Q5 XKv+kuYUk/4LzAH9v5HanoRULHkq+z+w3eQXY5JhpV3KyfFr70117wzMfZ/kJknddxMA 5uUg== 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=xOq5yyY/u+0O8ZudKc0fLqZJ0PgNfXdMDM0w1gmW1jw=; b=ZapVmULAKc2oS52llH9cGPoj1vKAe6EnnuEDmNDSXBhFW/LrEMN9Wn7iAHfR1uiT47 khWctVmAqnmzNjtQIjEMGZAntY4gcYULQjM5jdgvyCnWroqMnrDK2PHWzGH+HtL4K3ti Ai5DrpPJ4qeGYAR78fhnoYk89Q0T4AqTrX6DspBxCIRiwB0Jegdqc6vYvlY/VhD8Bgda YB7hrHKShOxjastrTKj4qmoDpmtLxtS7h+4hpoN69+ksxPOLs0qCgrP3tnqDudoDg/89 4bNSuuYeL9+nHHa+yuRc34WKjOkH+l82gPwZueGNN2zTjRqf83CyM7lesYmCkPAJ5NaD CqIw== X-Gm-Message-State: AOAM532vaGe6O034k6ya3LKM8HimdaXhPCxReWu4QjpglPoBJQ8VOsyk Z9lXOOjzUL5h+M81+/J6iFc= X-Google-Smtp-Source: ABdhPJyn2AB2ezg+28YzyfC8sKKmzSJ0tCVsEm3GVCDu3mVEnnRNRX38Gk2mKPG/lul462lAoHmanQ== X-Received: by 2002:ac2:5091:: with SMTP id f17mr683365lfm.166.1589506969603; Thu, 14 May 2020 18:42:49 -0700 (PDT) Received: from localhost.localdomain (ppp91-78-208-152.pppoe.mtu-net.ru. [91.78.208.152]) by smtp.gmail.com with ESMTPSA id i1sm309669lja.3.2020.05.14.18.42.48 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 14 May 2020 18:42:49 -0700 (PDT) From: Dmitry Osipenko To: Jens Axboe , Thierry Reding , Jonathan Hunter , =?utf-8?b?TWljaGHFgiBNaXJvc8WCYXc=?= , David Heidelberg , Peter Geis , Stephen Warren , Nicolas Chauvet , Ulf Hansson , Adrian Hunter , Billy Laws , =?utf-8?q?Nils_=C3=96stlund?= , Christoph Hellwig , Ard Biesheuvel , Davidlohr Bueso Cc: linux-tegra@vger.kernel.org, linux-block@vger.kernel.org, Andrey Danin , Gilles Grandou , Ryan Grachek , linux-mmc@vger.kernel.org, linux-kernel@vger.kernel.org, linux-efi Subject: [PATCH v4 2/6] mmc: block: Add mmc_bdev_to_card() helper Date: Fri, 15 May 2020 04:41:39 +0300 Message-Id: <20200515014143.12984-3-digetx@gmail.com> X-Mailer: git-send-email 2.26.0 In-Reply-To: <20200515014143.12984-1-digetx@gmail.com> References: <20200515014143.12984-1-digetx@gmail.com> MIME-Version: 1.0 Sender: linux-tegra-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-tegra@vger.kernel.org NVIDIA Tegra Partition Table takes into account MMC card's BOOT_SIZE_MULT parameter, and thus, the partition parser needs to retrieve that EXT_CSD value from the block device. There are also some other parts of struct mmc_card that are needed for the partition parser in order to calculate the eMMC offset and verify different things. This patch introduces new helper which takes block device for the input argument and returns the corresponding MMC card. Signed-off-by: Dmitry Osipenko --- drivers/mmc/core/block.c | 15 +++++++++++++++ include/linux/mmc/blkdev.h | 13 +++++++++++++ 2 files changed, 28 insertions(+) create mode 100644 include/linux/mmc/blkdev.h diff --git a/drivers/mmc/core/block.c b/drivers/mmc/core/block.c index c5367e2c8487..99298e888381 100644 --- a/drivers/mmc/core/block.c +++ b/drivers/mmc/core/block.c @@ -40,6 +40,7 @@ #include #include +#include #include #include #include @@ -305,6 +306,20 @@ static ssize_t force_ro_store(struct device *dev, struct device_attribute *attr, return ret; } +struct mmc_card *mmc_bdev_to_card(struct block_device *bdev) +{ + struct mmc_blk_data *md; + + if (bdev->bd_disk->major != MMC_BLOCK_MAJOR) + return NULL; + + md = mmc_blk_get(bdev->bd_disk); + if (!md) + return NULL; + + return md->queue.card; +} + static int mmc_blk_open(struct block_device *bdev, fmode_t mode) { struct mmc_blk_data *md = mmc_blk_get(bdev->bd_disk); diff --git a/include/linux/mmc/blkdev.h b/include/linux/mmc/blkdev.h new file mode 100644 index 000000000000..67608c58de70 --- /dev/null +++ b/include/linux/mmc/blkdev.h @@ -0,0 +1,13 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * linux/include/linux/mmc/blkdev.h + */ +#ifndef LINUX_MMC_BLOCK_DEVICE_H +#define LINUX_MMC_BLOCK_DEVICE_H + +struct block_device; +struct mmc_card; + +struct mmc_card *mmc_bdev_to_card(struct block_device *bdev); + +#endif /* LINUX_MMC_BLOCK_DEVICE_H */ From patchwork Fri May 15 01:41:40 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Dmitry Osipenko X-Patchwork-Id: 1290785 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=vger.kernel.org (client-ip=23.128.96.18; helo=vger.kernel.org; envelope-from=linux-tegra-owner@vger.kernel.org; receiver=) Authentication-Results: ozlabs.org; dmarc=pass (p=none dis=none) header.from=gmail.com Authentication-Results: ozlabs.org; dkim=pass (2048-bit key; unprotected) header.d=gmail.com header.i=@gmail.com header.a=rsa-sha256 header.s=20161025 header.b=PNJczpcd; dkim-atps=neutral Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by ozlabs.org (Postfix) with ESMTP id 49NWPr0XGVz9sTY for ; Fri, 15 May 2020 11:42:56 +1000 (AEST) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1728384AbgEOBmy (ORCPT ); Thu, 14 May 2020 21:42:54 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:55864 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1728365AbgEOBmx (ORCPT ); Thu, 14 May 2020 21:42:53 -0400 Received: from mail-lf1-x141.google.com (mail-lf1-x141.google.com [IPv6:2a00:1450:4864:20::141]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id D0A39C061A0C; Thu, 14 May 2020 18:42:52 -0700 (PDT) Received: by mail-lf1-x141.google.com with SMTP id a4so422548lfh.12; Thu, 14 May 2020 18:42:52 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; bh=SGToYZIO8U3/obGvzcffFr/KOjbT4Cz30vB/ntIZqLk=; b=PNJczpcdssfoQ3Lzu+M7bECiDXAOk1my3Do9Wh83LPZ6r/ofgcnqd3WJtQhoQXBsKI KxOtZ1XhSjBw6VT3AmHbwmChtm6FuAAbBCnb0CeuHdYeG6Uaq7qjHPu2lLDaAqlBYsP0 M/Tq8sP2GtAJ5cCUembrHagJ4sj9GSdt6RgaOObfTa/b1G7OAtXZtXQOZ2WNVkF2zVx1 nD3FJkL0VGgw5Ox3gfEQJvVdJvTeW/Jnse26GyFgz72DeTc0IhehNWw/9TzEsiOYIm8a k4dak440J1qQA6EH0+a6/SYa/7jGTHk7yiVSlOkWf11Ozf55pKLQuoPLNWw6PH4nZAXk 25VQ== 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=SGToYZIO8U3/obGvzcffFr/KOjbT4Cz30vB/ntIZqLk=; b=mQc29VGjBe7mDopDb/46uYZtIzva3UbbEtMJrJ0YwYvre2ZSt5W0gMpeKsKT5Vwdls ZzfNPRYGWICjiISKdqRpD3QvW7UKopX8bbTKUjgiA3yPnTzL2HVAU9s0NCUGJ4obXvfs hQJkjpBEPoHhng16yjt20OvR8R/ubMSObVW1m6vt7b0ZlMO9Z7NH7X+pjGnVnG7Pv5sM 5fbqvNOVjM6RBLN2mZ7Iulire3cuYo4cpJCIhmPQdQYiubBL9ug3OTLTjXpad84ypy14 QcT0/o1fDy+N8d/XDN5enTz2T8BkouS+IAUSWorEYR7Q1k8g7oa5c3Eh9j5hw44moo6t x/OA== X-Gm-Message-State: AOAM532M/FMho62JKHJSiljsaaxTcqaQxUAjcqepTOp704kPUHycn5E7 RzYNs9RcbNlMujfD3zwStLo= X-Google-Smtp-Source: ABdhPJy3DI034hMBxV+46OsFnSgzURtCD/HxB0Ka7447ixmY8EHyZpEFX9rxuKEsq6faXrPRPKEk7w== X-Received: by 2002:a19:6554:: with SMTP id c20mr462823lfj.140.1589506971089; Thu, 14 May 2020 18:42:51 -0700 (PDT) Received: from localhost.localdomain (ppp91-78-208-152.pppoe.mtu-net.ru. [91.78.208.152]) by smtp.gmail.com with ESMTPSA id i1sm309669lja.3.2020.05.14.18.42.49 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 14 May 2020 18:42:50 -0700 (PDT) From: Dmitry Osipenko To: Jens Axboe , Thierry Reding , Jonathan Hunter , =?utf-8?b?TWljaGHFgiBNaXJvc8WCYXc=?= , David Heidelberg , Peter Geis , Stephen Warren , Nicolas Chauvet , Ulf Hansson , Adrian Hunter , Billy Laws , =?utf-8?q?Nils_=C3=96stlund?= , Christoph Hellwig , Ard Biesheuvel , Davidlohr Bueso Cc: linux-tegra@vger.kernel.org, linux-block@vger.kernel.org, Andrey Danin , Gilles Grandou , Ryan Grachek , linux-mmc@vger.kernel.org, linux-kernel@vger.kernel.org, linux-efi Subject: [PATCH v4 3/6] partitions: Introduce NVIDIA Tegra Partition Table Date: Fri, 15 May 2020 04:41:40 +0300 Message-Id: <20200515014143.12984-4-digetx@gmail.com> X-Mailer: git-send-email 2.26.0 In-Reply-To: <20200515014143.12984-1-digetx@gmail.com> References: <20200515014143.12984-1-digetx@gmail.com> MIME-Version: 1.0 Sender: linux-tegra-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-tegra@vger.kernel.org All NVIDIA Tegra devices use a special partition table format for the internal storage partitioning. Most of Tegra devices have GPT partition in addition to TegraPT, but some older Android consumer-grade devices do not or GPT is placed in a wrong sector, and thus, the TegraPT is needed in order to support these devices properly by the upstream kernel. This patch adds support for NVIDIA Tegra Partition Table format that is used at least by all NVIDIA Tegra20 and Tegra30 devices. Tested-by: Nils Östlund Signed-off-by: Dmitry Osipenko --- arch/arm/mach-tegra/tegra.c | 54 ++++ block/partitions/Kconfig | 8 + block/partitions/Makefile | 1 + block/partitions/check.h | 1 + block/partitions/core.c | 3 + block/partitions/tegra.c | 565 ++++++++++++++++++++++++++++++++++ include/soc/tegra/bootdata.h | 46 +++ include/soc/tegra/common.h | 9 + include/soc/tegra/partition.h | 83 +++++ 9 files changed, 770 insertions(+) create mode 100644 block/partitions/tegra.c create mode 100644 include/soc/tegra/bootdata.h create mode 100644 include/soc/tegra/partition.h diff --git a/arch/arm/mach-tegra/tegra.c b/arch/arm/mach-tegra/tegra.c index c011359bcdb4..da6bcd85398b 100644 --- a/arch/arm/mach-tegra/tegra.c +++ b/arch/arm/mach-tegra/tegra.c @@ -28,7 +28,9 @@ #include +#include #include +#include #include #include @@ -62,9 +64,61 @@ u32 tegra_uart_config[3] = { 0, }; +static void __init tegra_boot_config_table_init(void) +{ + struct tegra30_boot_config_table __iomem *t30_bct; + struct tegra20_boot_config_table __iomem *t20_bct; + struct tegra20_boot_info_table __iomem *t20_bit; + u32 iram_end = TEGRA_IRAM_BASE + TEGRA_IRAM_SIZE; + u32 iram_start = TEGRA_IRAM_BASE; + u32 pt_addr, pt_size, bct_size; + + t20_bit = IO_ADDRESS(TEGRA_IRAM_BASE); + + if (of_machine_is_compatible("nvidia,tegra20")) { + bct_size = sizeof(*t20_bct); + + if (t20_bit->bct_size != bct_size || + t20_bit->bct_ptr < iram_start || + t20_bit->bct_ptr > iram_end - bct_size) + return; + + t20_bct = IO_ADDRESS(t20_bit->bct_ptr); + + if (t20_bct->boot_data_version != TEGRA_BOOTDATA_VERSION_T20) + return; + + pt_addr = t20_bct->partition_table_logical_sector_address; + pt_size = t20_bct->partition_table_num_logical_sectors; + + } else if (of_machine_is_compatible("nvidia,tegra30")) { + bct_size = sizeof(*t30_bct); + + if (t20_bit->bct_size != bct_size || + t20_bit->bct_ptr < iram_start || + t20_bit->bct_ptr > iram_end - bct_size) + return; + + t30_bct = IO_ADDRESS(t20_bit->bct_ptr); + + if (t30_bct->boot_data_version != TEGRA_BOOTDATA_VERSION_T30) + return; + + pt_addr = t30_bct->partition_table_logical_sector_address; + pt_size = t30_bct->partition_table_num_logical_sectors; + } else { + return; + } + + pr_info("%s: BCT found in IRAM\n", __func__); + + tegra_partition_table_setup(pt_addr, pt_size); +} + static void __init tegra_init_early(void) { of_register_trusted_foundations(); + tegra_boot_config_table_init(); tegra_cpu_reset_handler_init(); call_firmware_op(l2x0_init); } diff --git a/block/partitions/Kconfig b/block/partitions/Kconfig index 702689a628f0..2c1408cba1a6 100644 --- a/block/partitions/Kconfig +++ b/block/partitions/Kconfig @@ -268,3 +268,11 @@ config CMDLINE_PARTITION help Say Y here if you want to read the partition table from bootargs. The format for the command line is just like mtdparts. + +config TEGRA_PARTITION + bool "NVIDIA Tegra Partition support" if PARTITION_ADVANCED + default y if ARCH_TEGRA + depends on (ARCH_TEGRA && MMC_BLOCK) || COMPILE_TEST + help + Say Y here if you would like to be able to read the hard disk + partition table format used by NVIDIA Tegra machines. diff --git a/block/partitions/Makefile b/block/partitions/Makefile index a7f05cdb02a8..83cb70c6d08d 100644 --- a/block/partitions/Makefile +++ b/block/partitions/Makefile @@ -20,3 +20,4 @@ obj-$(CONFIG_IBM_PARTITION) += ibm.o obj-$(CONFIG_EFI_PARTITION) += efi.o obj-$(CONFIG_KARMA_PARTITION) += karma.o obj-$(CONFIG_SYSV68_PARTITION) += sysv68.o +obj-$(CONFIG_TEGRA_PARTITION) += tegra.o diff --git a/block/partitions/check.h b/block/partitions/check.h index c577e9ee67f0..ffa01cc4b0b0 100644 --- a/block/partitions/check.h +++ b/block/partitions/check.h @@ -67,4 +67,5 @@ int osf_partition(struct parsed_partitions *state); int sgi_partition(struct parsed_partitions *state); int sun_partition(struct parsed_partitions *state); int sysv68_partition(struct parsed_partitions *state); +int tegra_partition(struct parsed_partitions *state); int ultrix_partition(struct parsed_partitions *state); diff --git a/block/partitions/core.c b/block/partitions/core.c index 297004fd2264..0b4720372f07 100644 --- a/block/partitions/core.c +++ b/block/partitions/core.c @@ -81,6 +81,9 @@ static int (*check_part[])(struct parsed_partitions *) = { #endif #ifdef CONFIG_SYSV68_PARTITION sysv68_partition, +#endif +#ifdef CONFIG_TEGRA_PARTITION + tegra_partition, #endif NULL }; diff --git a/block/partitions/tegra.c b/block/partitions/tegra.c new file mode 100644 index 000000000000..d1b84fff362c --- /dev/null +++ b/block/partitions/tegra.c @@ -0,0 +1,565 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * NVIDIA Tegra Partition Table + * + * Copyright (C) 2020 GRATE-DRIVER project + * Copyright (C) 2020 Dmitry Osipenko + * + * Credits for the partition table format: + * + * Andrey Danin (Toshiba AC100 TegraPT format) + * Gilles Grandou (Toshiba AC100 TegraPT format) + * Ryan Grachek (Google TV "Molly" TegraPT format) + * Stephen Warren (Useful suggestions about eMMC/etc) + */ + +#define pr_fmt(fmt) "tegra-partition: " fmt + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include + +#include "check.h" + +#define TEGRA_PT_SECTOR_SIZE(ptp) ((ptp)->logical_sector_size / SZ_512) +#define TEGRA_PT_SECTOR(ptp, s) ((s) * TEGRA_PT_SECTOR_SIZE(ptp)) + +#define TEGRA_PT_HEADER_SIZE \ + (sizeof(struct tegra_partition_header_insecure) + \ + sizeof(struct tegra_partition_header_secure)) \ + +#define TEGRA_PT_MAX_PARTITIONS(ptp) \ + (((ptp)->logical_sector_size - TEGRA_PT_HEADER_SIZE) / \ + sizeof(struct tegra_partition)) + +#define TEGRA_PT_ERR(ptp, fmt, ...) \ + pr_debug("%s: " fmt, \ + (ptp)->state->bdev->bd_disk->disk_name, ##__VA_ARGS__) \ + +#define TEGRA_PT_PARSE_ERR(ptp, fmt, ...) \ + TEGRA_PT_ERR(ptp, "sector %llu: invalid " fmt, \ + (ptp)->sector, ##__VA_ARGS__) + +struct tegra_partition_table_parser { + struct tegra_partition_table *pt; + unsigned int logical_sector_size; + struct parsed_partitions *state; + bool pt_entry_checked; + sector_t sector; + int boot_offset; + u32 dev_instance; + u32 dev_id; +}; + +union tegra_partition_table_u { + struct tegra_partition_table pt; + u8 pt_parts[SZ_4K / SZ_512][SZ_512]; +}; + +struct tegra_partition_type { + unsigned int type; + char *name; +}; + +static sector_t tegra_pt_logical_sector_address; +static sector_t tegra_pt_logical_sectors_num; + +void tegra_partition_table_setup(unsigned int logical_sector_address, + unsigned int logical_sectors_num) +{ + tegra_pt_logical_sector_address = logical_sector_address; + tegra_pt_logical_sectors_num = logical_sectors_num; + + pr_info("initialized to logical sector = %llu sectors_num = %llu\n", + tegra_pt_logical_sector_address, tegra_pt_logical_sectors_num); +} + +/* + * Some partitions are very sensitive, changing data on them may brick device. + * + * For more details about partitions see: + * + * "https://docs.nvidia.com/jetson/l4t/Tegra Linux Driver Package Development Guide/part_config.html" + */ +static const char * const partitions_blacklist[] = { + "BCT", "EBT", "EB2", "EKS", "GP1", "GPT", "MBR", "PT", +}; + +static bool tegra_partition_name_match(struct tegra_partition *p, + const char *name) +{ + return !strncmp(p->partition_name, name, TEGRA_PT_NAME_SIZE); +} + +static bool tegra_partition_skip(struct tegra_partition *p, + struct tegra_partition_table_parser *ptp, + sector_t sector) +{ + unsigned int i; + + /* skip eMMC boot partitions */ + if (sector < ptp->boot_offset) + return true; + + for (i = 0; i < ARRAY_SIZE(partitions_blacklist); i++) { + if (tegra_partition_name_match(p, partitions_blacklist[i])) + return true; + } + + return false; +} + +static const struct tegra_partition_type tegra_partition_expected_types[] = { + { .type = TEGRA_PT_PART_TYPE_BCT, .name = "BCT", }, + { .type = TEGRA_PT_PART_TYPE_EBT, .name = "EBT", }, + { .type = TEGRA_PT_PART_TYPE_EBT, .name = "EB2", }, + { .type = TEGRA_PT_PART_TYPE_PT, .name = "PT", }, + { .type = TEGRA_PT_PART_TYPE_GP1, .name = "GP1", }, + { .type = TEGRA_PT_PART_TYPE_GPT, .name = "GPT", }, + { .type = TEGRA_PT_PART_TYPE_GENERIC, .name = NULL, }, +}; + +static int tegra_partition_type_valid(struct tegra_partition_table_parser *ptp, + struct tegra_partition *p) +{ + const struct tegra_partition_type *ptype; + unsigned int i; + + for (i = 0; i < ARRAY_SIZE(tegra_partition_expected_types); i++) { + ptype = &tegra_partition_expected_types[i]; + + if (ptype->name && !tegra_partition_name_match(p, ptype->name)) + continue; + + if (p->part_info.partition_type == ptype->type) + return 0; + + /* + * Unsure about all possible types, let's emit error and + * allow to continue for now. + */ + if (!ptype->name) + return 1; + } + + return -1; +} + +static bool tegra_partition_valid(struct tegra_partition_table_parser *ptp, + struct tegra_partition *p, + struct tegra_partition *prev, + sector_t sector, + sector_t size) +{ + struct tegra_partition_info *prev_pi = &prev->part_info; + sector_t sect_end = TEGRA_PT_SECTOR(ptp, + prev_pi->logical_sector_address + + prev_pi->logical_sectors_num); + char *type, name[2][TEGRA_PT_NAME_SIZE + 1]; + int err; + + strscpy(name[0], p->partition_name, sizeof(name[0])); + strscpy(name[1], prev->partition_name, sizeof(name[1])); + + /* validate expected partition name/type */ + err = tegra_partition_type_valid(ptp, p); + if (err) { + TEGRA_PT_PARSE_ERR(ptp, "partition_type: [%s] partition_type=%u\n", + name[0], p->part_info.partition_type); + if (err < 0) + return false; + + TEGRA_PT_ERR(ptp, "continuing, please update list of expected types\n"); + } + + /* validate partition table BCT addresses */ + if (tegra_partition_name_match(p, "PT")) { + if (sector != TEGRA_PT_SECTOR(ptp, tegra_pt_logical_sector_address) && + size != TEGRA_PT_SECTOR(ptp, tegra_pt_logical_sectors_num)) { + TEGRA_PT_PARSE_ERR(ptp, "PT location: sector=%llu size=%llu\n", + sector, size); + return false; + } + + if (ptp->pt_entry_checked) { + TEGRA_PT_PARSE_ERR(ptp, "(duplicated) PT\n"); + return false; + } + + ptp->pt_entry_checked = true; + } + + if (sector + size < sector) { + TEGRA_PT_PARSE_ERR(ptp, "size: [%s] integer overflow sector=%llu size=%llu\n", + name[0], sector, size); + return false; + } + + /* validate allocation_policy=sequential (absolute unsupported) */ + if (p != prev && sect_end > sector) { + TEGRA_PT_PARSE_ERR(ptp, "allocation_policy: [%s] end=%llu [%s] sector=%llu size=%llu\n", + name[1], sect_end, name[0], sector, size); + return false; + } + + if (ptp->dev_instance != p->mount_info.device_instance) { + TEGRA_PT_PARSE_ERR(ptp, "device_instance: [%s] device_instance=%u|%u\n", + name[0], ptp->dev_instance, + p->mount_info.device_instance); + return false; + } + + if (ptp->dev_id != p->mount_info.device_id) { + TEGRA_PT_PARSE_ERR(ptp, "device_id: [%s] device_id=%u|%u\n", + name[0], ptp->dev_id, + p->mount_info.device_id); + return false; + } + + if (p->partition_id > 127) { + TEGRA_PT_PARSE_ERR(ptp, "partition_id: [%s] partition_id=%u\n", + name[0], p->partition_id); + return false; + } + + sect_end = get_capacity(ptp->state->bdev->bd_disk); + + /* eMMC boot partitions are below ptp->boot_offset */ + if (sector < ptp->boot_offset) { + sect_end += ptp->boot_offset; + type = "boot"; + } else { + sector -= ptp->boot_offset; + type = "main"; + } + + /* validate size */ + if (!size || sector + size > sect_end) { + TEGRA_PT_PARSE_ERR(ptp, "size: [%s] %s partition boot_offt=%d end=%llu sector=%llu size=%llu\n", + name[0], type, ptp->boot_offset, sect_end, + sector, size); + return false; + } + + return true; +} + +static bool tegra_partitions_parsed(struct tegra_partition_table_parser *ptp, + bool check_only) +{ + struct parsed_partitions *state = ptp->state; + struct tegra_partition_table *pt = ptp->pt; + sector_t sector, size; + int i, slot = 1; + + ptp->pt_entry_checked = false; + + for (i = 0; i < pt->secure.num_partitions; i++) { + struct tegra_partition *p = &pt->partitions[i]; + struct tegra_partition *prev = &pt->partitions[max(i - 1, 0)]; + struct tegra_partition_info *pi = &p->part_info; + + if (slot == state->limit && !check_only) + break; + + sector = TEGRA_PT_SECTOR(ptp, pi->logical_sector_address); + size = TEGRA_PT_SECTOR(ptp, pi->logical_sectors_num); + + if (check_only && + !tegra_partition_valid(ptp, p, prev, sector, size)) + return false; + + if (check_only || + tegra_partition_skip(p, ptp, sector)) + continue; + + put_partition(state, slot++, sector - ptp->boot_offset, size); + } + + if (check_only && !ptp->pt_entry_checked) { + TEGRA_PT_PARSE_ERR(ptp, "PT: table entry not found\n"); + return false; + } + + return true; +} + +static bool +tegra_partition_table_parsed(struct tegra_partition_table_parser *ptp) +{ + if (ptp->pt->secure.num_partitions == 0 || + ptp->pt->secure.num_partitions > TEGRA_PT_MAX_PARTITIONS(ptp)) { + TEGRA_PT_PARSE_ERR(ptp, "num_partitions=%u\n", + ptp->pt->secure.num_partitions); + return false; + } + + return tegra_partitions_parsed(ptp, true) && + tegra_partitions_parsed(ptp, false); +} + +static int +tegra_partition_table_insec_hdr_valid(struct tegra_partition_table_parser *ptp) +{ + if (ptp->pt->insecure.magic != TEGRA_PT_MAGIC || + ptp->pt->insecure.version != TEGRA_PT_VERSION) { + TEGRA_PT_PARSE_ERR(ptp, "insecure header: magic=0x%llx ver=0x%x\n", + ptp->pt->insecure.magic, + ptp->pt->insecure.version); + return 0; + } + + return 1; +} + +static int +tegra_partition_table_sec_hdr_valid(struct tegra_partition_table_parser *ptp) +{ + size_t pt_size = ptp->pt->secure.num_partitions; + + pt_size *= sizeof(ptp->pt->partitions[0]); + pt_size += TEGRA_PT_HEADER_SIZE; + + if (ptp->pt->secure.magic != TEGRA_PT_MAGIC || + ptp->pt->secure.version != TEGRA_PT_VERSION || + ptp->pt->secure.length != ptp->pt->insecure.length || + ptp->pt->secure.length < pt_size) { + TEGRA_PT_PARSE_ERR(ptp, "secure header: magic=0x%llx ver=0x%x length=%u|%u|%zu\n", + ptp->pt->secure.magic, + ptp->pt->secure.version, + ptp->pt->secure.length, + ptp->pt->insecure.length, + pt_size); + return 0; + } + + return 1; +} + +static int +tegra_partition_table_unencrypted(struct tegra_partition_table_parser *ptp) +{ + /* AES IV, all zeros if unencrypted */ + if (ptp->pt->secure.random_data[0] || ptp->pt->secure.random_data[1] || + ptp->pt->secure.random_data[2] || ptp->pt->secure.random_data[3]) { + pr_err_once("encrypted partition table unsupported\n"); + return 0; + } + + return 1; +} + +static int tegra_read_partition_table(struct tegra_partition_table_parser *ptp) +{ + union tegra_partition_table_u *ptu = (typeof(ptu))ptp->pt; + unsigned int i; + Sector sect; + void *part; + + for (i = 0; i < ptp->logical_sector_size / SZ_512; i++) { + /* + * Partition table takes at maximum 4096 bytes, but + * read_part_sector() guarantees only that SECTOR_SIZE will + * be read at minimum. + */ + part = read_part_sector(ptp->state, ptp->sector + i, §); + if (!part) { + TEGRA_PT_ERR(ptp, "failed to read sector %llu\n", + ptp->sector + i); + return 0; + } + + memcpy(ptu->pt_parts[i], part, SZ_512); + put_dev_sector(sect); + } + + return 1; +} + +static int tegra_partition_scan(struct tegra_partition_table_parser *ptp) +{ + sector_t start_sector, num_sectors; + int ret = 0; + + num_sectors = TEGRA_PT_SECTOR(ptp, tegra_pt_logical_sectors_num); + start_sector = TEGRA_PT_SECTOR(ptp, tegra_pt_logical_sector_address); + + if (start_sector < ptp->boot_offset) { + TEGRA_PT_ERR(ptp, + "scanning eMMC boot partitions unimplemented\n"); + return 0; + } + + ptp->sector = start_sector - ptp->boot_offset; + + /* + * Partition table is duplicated for num_sectors. + * If first table is corrupted, we will try next. + */ + while (num_sectors--) { + ret = tegra_read_partition_table(ptp); + if (!ret) + goto next_sector; + + ret = tegra_partition_table_insec_hdr_valid(ptp); + if (!ret) + goto next_sector; + + ret = tegra_partition_table_unencrypted(ptp); + if (!ret) + goto next_sector; + + ret = tegra_partition_table_sec_hdr_valid(ptp); + if (!ret) + goto next_sector; + + ret = tegra_partition_table_parsed(ptp); + if (ret) + break; +next_sector: + ptp->sector += TEGRA_PT_SECTOR_SIZE(ptp); + } + + return ret; +} + +static const u32 tegra20_sdhci_bases[TEGRA_PT_SDHCI_DEVICE_INSTANCES] = { + 0xc8000000, 0xc8000200, 0xc8000400, 0xc8000600, +}; + +static const u32 tegra30_sdhci_bases[TEGRA_PT_SDHCI_DEVICE_INSTANCES] = { + 0x78000000, 0x78000200, 0x78000400, 0x78000600, +}; + +static const struct of_device_id tegra_sdhci_match[] = { + { .compatible = "nvidia,tegra20-sdhci", .data = tegra20_sdhci_bases, }, + { .compatible = "nvidia,tegra30-sdhci", .data = tegra30_sdhci_bases, }, + {} +}; + +static int +tegra_partition_table_emmc_boot_offset(struct tegra_partition_table_parser *ptp) +{ + struct mmc_card *card = mmc_bdev_to_card(ptp->state->bdev); + const struct of_device_id *matched; + const u32 *sdhci_bases; + u32 sdhci_base; + unsigned int i; + int err; + + /* filter out unexpected/untested boot sources */ + if (!card || card->ext_csd.rev < 3 || + !mmc_card_is_blockaddr(card) || + mmc_card_is_removable(card->host) || + bdev_logical_block_size(ptp->state->bdev) != SZ_512) + return -1; + + /* skip everything unrelated to Tegra eMMC */ + matched = of_match_node(tegra_sdhci_match, card->host->parent->of_node); + if (!matched) + return -1; + + sdhci_bases = matched->data; + + /* figure out SDHCI instance ID by the base address */ + err = of_property_read_u32_index(card->host->parent->of_node, + "reg", 0, &sdhci_base); + if (err) + return -1; + + for (i = 0; i < TEGRA_PT_SDHCI_DEVICE_INSTANCES; i++) { + if (sdhci_base == sdhci_bases[i]) + break; + } + + if (i == TEGRA_PT_SDHCI_DEVICE_INSTANCES) + return -1; + + ptp->dev_id = TEGRA_PT_SDHCI_DEVICE_ID; + ptp->dev_instance = i; + + /* + * eMMC storage has two special boot partitions in addition to the + * main one. NVIDIA's bootloader linearizes eMMC boot0->boot1->main + * accesses, this means that the partition table addresses are shifted + * by the size of boot partitions. In accordance with the eMMC + * specification, the boot partition size is calculated as follows: + * + * boot partition size = 128K byte x BOOT_SIZE_MULT + * + * This function returns number of sectors occupied by the both boot + * partitions. + */ + return card->ext_csd.raw_boot_mult * SZ_128K / + SZ_512 * MMC_NUM_BOOT_PARTITION; +} + +/* + * Logical sector size may vary per device model and apparently there is no + * way to get information about the size from kernel. The info is hardcoded + * into bootloader and it doesn't tell us, so we'll just try all possible + * well-known sizes until succeed. + * + * For example Samsung Galaxy Tab 10.1 uses 2K sectors. While Acer A500, + * Nexus 7 and Ouya are using 4K sectors. + */ +static const unsigned int tegra_pt_logical_sector_sizes[] = { + SZ_4K, SZ_2K, +}; + +/* + * The 'tegraboot=' command line option is supplied by NVIDIA + * bootloader. + */ +static bool tegra_boot_sdmmc; +static int __init tegra_boot_fn(char *str) +{ + tegra_boot_sdmmc = !strcmp(str, "sdmmc"); + return 1; +} +__setup("tegraboot=", tegra_boot_fn); + +int tegra_partition(struct parsed_partitions *state) +{ + struct tegra_partition_table_parser ptp = {}; + unsigned int i; + int ret; + + if (!soc_is_tegra() || !tegra_boot_sdmmc) + return 0; + + ptp.state = state; + + ptp.boot_offset = tegra_partition_table_emmc_boot_offset(&ptp); + if (ptp.boot_offset < 0) + return 0; + + ptp.pt = kmalloc(SZ_4K, GFP_KERNEL); + if (!ptp.pt) + return 0; + + for (i = 0; i < ARRAY_SIZE(tegra_pt_logical_sector_sizes); i++) { + ptp.logical_sector_size = tegra_pt_logical_sector_sizes[i]; + + ret = tegra_partition_scan(&ptp); + if (ret == 1) { + strlcat(state->pp_buf, "\n", PAGE_SIZE); + break; + } + } + + kfree(ptp.pt); + + return ret; +} diff --git a/include/soc/tegra/bootdata.h b/include/soc/tegra/bootdata.h new file mode 100644 index 000000000000..7be207cb2519 --- /dev/null +++ b/include/soc/tegra/bootdata.h @@ -0,0 +1,46 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ + +#ifndef __SOC_TEGRA_BOOTDATA_H__ +#define __SOC_TEGRA_BOOTDATA_H__ + +#include +#include + +#define TEGRA_BOOTDATA_VERSION_T20 NVBOOT_BOOTDATA_VERSION(0x2, 0x1) +#define TEGRA_BOOTDATA_VERSION_T30 NVBOOT_BOOTDATA_VERSION(0x3, 0x1) + +#define NVBOOT_BOOTDATA_VERSION(a, b) ((((a) & 0xffff) << 16) | \ + ((b) & 0xffff)) +#define NVBOOT_CMAC_AES_HASH_LENGTH 4 + +struct tegra20_boot_info_table { + u32 unused_data1[14]; + u32 bct_size; + u32 bct_ptr; +} __packed; + +struct tegra20_boot_config_table { + u32 crypto_hash[NVBOOT_CMAC_AES_HASH_LENGTH]; + u32 random_aes_blk[NVBOOT_CMAC_AES_HASH_LENGTH]; + u32 boot_data_version; + u32 unused_data1[712]; + u32 unused_consumer_data1; + u16 partition_table_logical_sector_address; + u16 partition_table_num_logical_sectors; + u32 unused_consumer_data[294]; + u32 unused_data[3]; +} __packed; + +struct tegra30_boot_config_table { + u32 crypto_hash[NVBOOT_CMAC_AES_HASH_LENGTH]; + u32 random_aes_blk[NVBOOT_CMAC_AES_HASH_LENGTH]; + u32 boot_data_version; + u32 unused_data1[1016]; + u32 unused_consumer_data1; + u16 partition_table_logical_sector_address; + u16 partition_table_num_logical_sectors; + u32 unused_consumer_data[502]; + u32 unused_data[3]; +} __packed; + +#endif /* __SOC_TEGRA_BOOTDATA_H__ */ diff --git a/include/soc/tegra/common.h b/include/soc/tegra/common.h index 98027a76ce3d..744280ecab5f 100644 --- a/include/soc/tegra/common.h +++ b/include/soc/tegra/common.h @@ -6,6 +6,15 @@ #ifndef __SOC_TEGRA_COMMON_H__ #define __SOC_TEGRA_COMMON_H__ +#include + +#ifdef CONFIG_ARCH_TEGRA bool soc_is_tegra(void); +#else +static inline bool soc_is_tegra(void) +{ + return false; +} +#endif #endif /* __SOC_TEGRA_COMMON_H__ */ diff --git a/include/soc/tegra/partition.h b/include/soc/tegra/partition.h new file mode 100644 index 000000000000..4e424543973c --- /dev/null +++ b/include/soc/tegra/partition.h @@ -0,0 +1,83 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ + +#ifndef __SOC_TEGRA_PARTITION_H__ +#define __SOC_TEGRA_PARTITION_H__ + +#include +#include + +#define TEGRA_PT_MAGIC 0xffffffff8f9e8d8bULL +#define TEGRA_PT_VERSION 0x100 +#define TEGRA_PT_AES_HASH_SIZE 4 +#define TEGRA_PT_NAME_SIZE 4 + +#define TEGRA_PT_SDHCI_DEVICE_ID 18 +#define TEGRA_PT_SDHCI_DEVICE_INSTANCES 4 + +#define TEGRA_PT_PART_TYPE_BCT 1 +#define TEGRA_PT_PART_TYPE_EBT 2 +#define TEGRA_PT_PART_TYPE_PT 3 +#define TEGRA_PT_PART_TYPE_GENERIC 6 +#define TEGRA_PT_PART_TYPE_GP1 9 +#define TEGRA_PT_PART_TYPE_GPT 10 + +struct tegra_partition_mount_info { + u32 device_id; + u32 device_instance; + u32 device_attr; + u8 mount_path[TEGRA_PT_NAME_SIZE]; + u32 file_system_type; + u32 file_system_attr; +} __packed; + +struct tegra_partition_info { + u32 partition_attr; + u32 __pad1; + u64 logical_sector_address; + u64 logical_sectors_num; + u64 __pad2[2]; + u32 partition_type; + u32 __pad3; +} __packed; + +struct tegra_partition { + u32 partition_id; + u8 partition_name[TEGRA_PT_NAME_SIZE]; + struct tegra_partition_mount_info mount_info; + struct tegra_partition_info part_info; +} __packed; + +struct tegra_partition_header_insecure { + u64 magic; + u32 version; + u32 length; + u32 signature[TEGRA_PT_AES_HASH_SIZE]; +} __packed; + +struct tegra_partition_header_secure { + u32 random_data[TEGRA_PT_AES_HASH_SIZE]; + u64 magic; + u32 version; + u32 length; + u32 num_partitions; + u32 __pad; +} __packed; + +struct tegra_partition_table { + struct tegra_partition_header_insecure insecure; + struct tegra_partition_header_secure secure; + struct tegra_partition partitions[]; +} __packed; + +#ifdef CONFIG_TEGRA_PARTITION +void tegra_partition_table_setup(unsigned int logical_sector_address, + unsigned int logical_sectors_num); +#else +static inline void +tegra_partition_table_setup(unsigned int logical_sector_address, + unsigned int logical_sectors_num) +{ +} +#endif + +#endif /* __SOC_TEGRA_PARTITION_H__ */ From patchwork Fri May 15 01:41:41 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Dmitry Osipenko X-Patchwork-Id: 1290788 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=vger.kernel.org (client-ip=23.128.96.18; helo=vger.kernel.org; envelope-from=linux-tegra-owner@vger.kernel.org; receiver=) Authentication-Results: ozlabs.org; dmarc=pass (p=none dis=none) header.from=gmail.com Authentication-Results: ozlabs.org; dkim=pass (2048-bit key; unprotected) header.d=gmail.com header.i=@gmail.com header.a=rsa-sha256 header.s=20161025 header.b=RawQUcqC; dkim-atps=neutral Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by ozlabs.org (Postfix) with ESMTP id 49NWQD3NWSz9sTN for ; Fri, 15 May 2020 11:43:16 +1000 (AEST) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1728258AbgEOBnM (ORCPT ); Thu, 14 May 2020 21:43:12 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:55872 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1728372AbgEOBmy (ORCPT ); Thu, 14 May 2020 21:42:54 -0400 Received: from mail-lj1-x244.google.com (mail-lj1-x244.google.com [IPv6:2a00:1450:4864:20::244]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id E371EC05BD43; Thu, 14 May 2020 18:42:53 -0700 (PDT) Received: by mail-lj1-x244.google.com with SMTP id l19so453266lje.10; Thu, 14 May 2020 18:42:53 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; bh=EXpSXkZ/8Hfb2Ijnh+LYOs0qAyDxWCL/20mt+D8uMOs=; b=RawQUcqCrY6FrUwunWV9jJ1fcJHOQgZ2Fi5I+37lY73PGpBBngX9TN+0xsN9yNRVrJ xRTrcz4FbAKvanXkCqlN1GPcpSWu+S6X1GtYDW1cyinoDTqCR3Gk/BM9M35lssG7ZA28 6E0F1Y1RUIwT0rVyx/dcChZw3NAj6i482cIRqFp+hlXqDxIwUy2U2GyhKq4eKCKt+WQl LRrwhpm8ZG8yZEREeH2jtfYQVtwcNybyMpm5Df+VdcufYCmVBLUXyFM3d1ldXKFVhXsn pN0ZNKpv0l+SsaaoT62qYoq63Slleb4z3T4BP0Xb4Q3WgdJcJi8TuBm48rKs5KCus1vD WsoQ== 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=EXpSXkZ/8Hfb2Ijnh+LYOs0qAyDxWCL/20mt+D8uMOs=; b=iPGGPnqrbbeP2gXF9dfRo8sGVOzfanVky8jGCqQ/XKL+Y6VQdovJoQw9QLV7526tR8 MQNfJn+uG65T8BTQrf2MFnSy5X3g1y3eP6TDvZmNkpyQd+8vf//VaaDw1BI4j7gk9oU8 dMCUHGblb+0/I+QDce4HqXBA2Hs191hix8R7pxLAeyh3TC1v2vJ7pDUjfemAaPyGkoEA 6DESPP69zQ4ggGV6m6LRsvLl+QjBnlU4JrwCx0RQppXeebwQaq+K4JFthKy0Oxeq0eov dLQoD13dM01waUugZQewUajd4qTnOHsN9ZqfLjU+L4YPkYCrrM7Wtb6HKw2VqIgwY0nz g+xw== X-Gm-Message-State: AOAM531aeK/htkcLzL4MIItGOZv2a7jXmzYGbErp+ox7ipIA+qUosz2E dcawe32QuAzXmnksHEq52R8= X-Google-Smtp-Source: ABdhPJwr2EMETnVN2svJMlP8kCCTDQFS2h557wuuZzhTHrIFzk1EcO74ZC4ircAssigCeiAO03nwFA== X-Received: by 2002:a2e:98c1:: with SMTP id s1mr704285ljj.9.1589506972397; Thu, 14 May 2020 18:42:52 -0700 (PDT) Received: from localhost.localdomain (ppp91-78-208-152.pppoe.mtu-net.ru. [91.78.208.152]) by smtp.gmail.com with ESMTPSA id i1sm309669lja.3.2020.05.14.18.42.51 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 14 May 2020 18:42:51 -0700 (PDT) From: Dmitry Osipenko To: Jens Axboe , Thierry Reding , Jonathan Hunter , =?utf-8?b?TWljaGHFgiBNaXJvc8WCYXc=?= , David Heidelberg , Peter Geis , Stephen Warren , Nicolas Chauvet , Ulf Hansson , Adrian Hunter , Billy Laws , =?utf-8?q?Nils_=C3=96stlund?= , Christoph Hellwig , Ard Biesheuvel , Davidlohr Bueso Cc: linux-tegra@vger.kernel.org, linux-block@vger.kernel.org, Andrey Danin , Gilles Grandou , Ryan Grachek , linux-mmc@vger.kernel.org, linux-kernel@vger.kernel.org, linux-efi Subject: [PATCH v4 4/6] partitions/efi: Support GPT entry lookup at a non-standard location Date: Fri, 15 May 2020 04:41:41 +0300 Message-Id: <20200515014143.12984-5-digetx@gmail.com> X-Mailer: git-send-email 2.26.0 In-Reply-To: <20200515014143.12984-1-digetx@gmail.com> References: <20200515014143.12984-1-digetx@gmail.com> MIME-Version: 1.0 Sender: linux-tegra-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-tegra@vger.kernel.org Most of consumer-grade NVIDIA Tegra devices use a proprietary bootloader that can't be easily replaced because it's locked down using Secure Boot cryptography singing and the crypto keys aren't given to a device owner. These devices usually have eMMC storage that is partitioned using a custom NVIDIA Tegra partition table format. Of course bootloader and other "special things" are stored on the eMMC storage, and thus, the partition format can't be changed. The Tegra partition format has been reverse-engineered, but NVIDIA did another odd thing by merging "boot" and "main" eMMC HW partitions into a single virtual partition in theirs bootloader. This is not supported by Linux kernel and can't be easily implemented. Hence partition table entry isn't accessible by kernel if it's located at the "boot" eMMC partition. Luckily this is a rare case in practice and even if it's the case, likely that the proprietary bootloader will supply kernel with a non-standard gpt_sector= cmdline option. This gpt_sector= argument points at a GPT entry that is placed at a non-standard location on the eMMC storage. This patch allows to support the non-standard cmdline option for NVIDIA Tegra devices without bothering any other platforms. The force_gpt_sector variable should be set before invoking efi_partition() and be unset after the invocation completion. This variable, if set, instructs GPT parser to look up GPT entry at the given sector in addition to the standard GPT locations. This patch is based on the original work done by Colin Cross for the downstream Android kernel. Signed-off-by: Dmitry Osipenko --- block/partitions/efi.c | 10 ++++++++++ block/partitions/efi.h | 2 ++ 2 files changed, 12 insertions(+) diff --git a/block/partitions/efi.c b/block/partitions/efi.c index b64bfdd4326c..48e4c2aeeded 100644 --- a/block/partitions/efi.c +++ b/block/partitions/efi.c @@ -103,6 +103,12 @@ force_gpt_fn(char *str) } __setup("gpt", force_gpt_fn); +/* Used by NVIDIA Tegra partition parser in order to convey a non-standard + * location of the GPT entry for lookup. This variable should be set before + * efi_partition() invocation for instructing parser to look up GPT entry at + * the given sector, and it should be unset after completion of the invocation. + */ +sector_t force_gpt_sector; /** * efi_crc32() - EFI version of crc32 function @@ -621,6 +627,10 @@ static int find_valid_gpt(struct parsed_partitions *state, gpt_header **gpt, if (!good_agpt && force_gpt) good_agpt = is_gpt_valid(state, lastlba, &agpt, &aptes); + if (!good_agpt && force_gpt && force_gpt_sector) + good_agpt = is_gpt_valid(state, force_gpt_sector, + &agpt, &aptes); + /* The obviously unsuccessful case */ if (!good_pgpt && !good_agpt) goto fail; diff --git a/block/partitions/efi.h b/block/partitions/efi.h index 8cc2b88d0aa8..630cf21439af 100644 --- a/block/partitions/efi.h +++ b/block/partitions/efi.h @@ -113,4 +113,6 @@ typedef struct _legacy_mbr { __le16 signature; } __packed legacy_mbr; +extern sector_t force_gpt_sector; + #endif From patchwork Fri May 15 01:41:42 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Dmitry Osipenko X-Patchwork-Id: 1290787 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=vger.kernel.org (client-ip=23.128.96.18; helo=vger.kernel.org; envelope-from=linux-tegra-owner@vger.kernel.org; receiver=) Authentication-Results: ozlabs.org; dmarc=pass (p=none dis=none) header.from=gmail.com Authentication-Results: ozlabs.org; dkim=pass (2048-bit key; unprotected) header.d=gmail.com header.i=@gmail.com header.a=rsa-sha256 header.s=20161025 header.b=hoPx86lk; dkim-atps=neutral Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by ozlabs.org (Postfix) with ESMTP id 49NWQ53yx1z9sTZ for ; Fri, 15 May 2020 11:43:09 +1000 (AEST) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1728466AbgEOBnC (ORCPT ); Thu, 14 May 2020 21:43:02 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:55878 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1728400AbgEOBm4 (ORCPT ); Thu, 14 May 2020 21:42:56 -0400 Received: from mail-lj1-x242.google.com (mail-lj1-x242.google.com [IPv6:2a00:1450:4864:20::242]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 672DBC061A0C; Thu, 14 May 2020 18:42:55 -0700 (PDT) Received: by mail-lj1-x242.google.com with SMTP id u15so489357ljd.3; Thu, 14 May 2020 18:42:55 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; bh=JVySzFwgY7e8nHIHJ3dU/d0fc76IF5fhtoXaTUTq3/w=; b=hoPx86lkMv329DILvtpon/Ajyu7+1OY5peruM7Vg7+OAXk+r+u7VTEqeBI+fmttHtB /RGZ79ojlFV98bYnoLGwRB/pr0w/iPGJwSJOp9NS05gIssx2cos+rU2DyX4HPL+66ohJ t5aFvt7PrCrUu79cvVD00vCpzZubK8MizHyf1rxztNhRROl1ur4byd/Hk5hTwEV3BcAr MTWn6M6FkwILuWpkHkHe1LFb3hqmhtxb1fSVCvWKmcisQLT46z6SY7ZfYE76Bx1W+kgK QdN5qSbO3gi55jgShl3JntW2B46hWZt8Y53TMnfC90PCN43Ge3X4GBPMA60lg3KqPek7 3XUQ== 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=JVySzFwgY7e8nHIHJ3dU/d0fc76IF5fhtoXaTUTq3/w=; b=Y91qKHyJJ1+2F0lLEtzE4CPHTszddjUll+Wqro8VsZ5VldV6tRn5BKz7394S7mHhAB i1clpTBJJRB9wZ5OKfAaqq4Kll+ROvFI6kymhNFgBElk04KB3sZgz++oMoX8pjRdzuZR /533PDWi+Wnx0cPQ0CUN3rHjanUUYsXImWwpHxWXb62RJZXVynyaK2ElUYk5W6/40NUb f1shMm1nq9dRtvSLoYonnsUf7PA3OrbDyjlIGAN/7Koo0WcRULaDdQVuaI1O71dFjqDl 4x5U7iWpcxLpizbCaehXfjvAXg6YSbcVHvYoD/teH/Daytkqrb3c1l/boGPDXXodpMaU UMow== X-Gm-Message-State: AOAM531+DvwVMcj4VUU37viJR5LmfTlxKZ/FbdjgQP1fKnOdt1D1gJmt nrB7jIknkbpQ0VeQed5rkPA= X-Google-Smtp-Source: ABdhPJxkl15/TS/h0JiR0KBnsPh+lDA/C79Y/X8zJyP/oDmmlGQXUNVcNHzTOB+r9/XLVL38oaoUpA== X-Received: by 2002:a2e:b4a5:: with SMTP id q5mr701391ljm.58.1589506973705; Thu, 14 May 2020 18:42:53 -0700 (PDT) Received: from localhost.localdomain (ppp91-78-208-152.pppoe.mtu-net.ru. [91.78.208.152]) by smtp.gmail.com with ESMTPSA id i1sm309669lja.3.2020.05.14.18.42.52 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 14 May 2020 18:42:53 -0700 (PDT) From: Dmitry Osipenko To: Jens Axboe , Thierry Reding , Jonathan Hunter , =?utf-8?b?TWljaGHFgiBNaXJvc8WCYXc=?= , David Heidelberg , Peter Geis , Stephen Warren , Nicolas Chauvet , Ulf Hansson , Adrian Hunter , Billy Laws , =?utf-8?q?Nils_=C3=96stlund?= , Christoph Hellwig , Ard Biesheuvel , Davidlohr Bueso Cc: linux-tegra@vger.kernel.org, linux-block@vger.kernel.org, Andrey Danin , Gilles Grandou , Ryan Grachek , linux-mmc@vger.kernel.org, linux-kernel@vger.kernel.org, linux-efi Subject: [PATCH v4 5/6] partitions/tegra: Support gpt_sector= command line option Date: Fri, 15 May 2020 04:41:42 +0300 Message-Id: <20200515014143.12984-6-digetx@gmail.com> X-Mailer: git-send-email 2.26.0 In-Reply-To: <20200515014143.12984-1-digetx@gmail.com> References: <20200515014143.12984-1-digetx@gmail.com> MIME-Version: 1.0 Sender: linux-tegra-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-tegra@vger.kernel.org The gpt_sector= causes the GPT partition parser to look at the specified sector for a valid GPT header if the GPT is not found at the beginning or the end of a block device. This is needed by Tegra-based devices that have TegraPT and GPT placed in inaccessible by kernel locations. The GPT entry duplicates TegraPT partitions. Signed-off-by: Dmitry Osipenko --- block/partitions/check.h | 1 + block/partitions/core.c | 1 + block/partitions/efi.c | 6 ++++++ block/partitions/tegra.c | 38 ++++++++++++++++++++++++++++++++++++++ 4 files changed, 46 insertions(+) diff --git a/block/partitions/check.h b/block/partitions/check.h index ffa01cc4b0b0..ff07435b3ac3 100644 --- a/block/partitions/check.h +++ b/block/partitions/check.h @@ -67,5 +67,6 @@ int osf_partition(struct parsed_partitions *state); int sgi_partition(struct parsed_partitions *state); int sun_partition(struct parsed_partitions *state); int sysv68_partition(struct parsed_partitions *state); +int tegra_partition_gpt(struct parsed_partitions *state); int tegra_partition(struct parsed_partitions *state); int ultrix_partition(struct parsed_partitions *state); diff --git a/block/partitions/core.c b/block/partitions/core.c index 0b4720372f07..ece70f15f24d 100644 --- a/block/partitions/core.c +++ b/block/partitions/core.c @@ -83,6 +83,7 @@ static int (*check_part[])(struct parsed_partitions *) = { sysv68_partition, #endif #ifdef CONFIG_TEGRA_PARTITION + tegra_partition_gpt, tegra_partition, #endif NULL diff --git a/block/partitions/efi.c b/block/partitions/efi.c index 48e4c2aeeded..f3b26be2bd6e 100644 --- a/block/partitions/efi.c +++ b/block/partitions/efi.c @@ -98,6 +98,12 @@ static int force_gpt; static int __init force_gpt_fn(char *str) { + /* This check allows to parse "gpt gpt_sector=" properly since + * "gpt" overlaps with "gpt_sector", see tegra_gpt_sector_fn(). + */ + if (force_gpt) + return 0; + force_gpt = 1; return 1; } diff --git a/block/partitions/tegra.c b/block/partitions/tegra.c index d1b84fff362c..c2dae0f32c2a 100644 --- a/block/partitions/tegra.c +++ b/block/partitions/tegra.c @@ -30,6 +30,7 @@ #include #include +#include "efi.h" #include "check.h" #define TEGRA_PT_SECTOR_SIZE(ptp) ((ptp)->logical_sector_size / SZ_512) @@ -563,3 +564,40 @@ int tegra_partition(struct parsed_partitions *state) return ret; } + +/* + * This allows a kernel command line option 'gpt_sector=' to + * enable GPT header lookup at a non-standard location. This option + * is given to kernel by a proprietary bootloader, which is used by + * *most* (but not all) of NVIDIA Tegra-based devices. + */ +static sector_t tegra_gpt_sector; +static int __init tegra_gpt_sector_fn(char *str) +{ + WARN_ON(kstrtoull(str, 10, &tegra_gpt_sector) < 0); + return 1; +} +__setup("gpt_sector=", tegra_gpt_sector_fn); + +int tegra_partition_gpt(struct parsed_partitions *state) +{ + int ret = 0; + +#ifdef CONFIG_EFI_PARTITION + struct tegra_partition_table_parser ptp = {}; + + if (!soc_is_tegra() || !tegra_boot_sdmmc || !tegra_gpt_sector) + return 0; + + ptp.state = state; + + ptp.boot_offset = tegra_partition_table_emmc_boot_offset(&ptp); + if (ptp.boot_offset < 0) + return 0; + + force_gpt_sector = tegra_gpt_sector; + ret = efi_partition(ptp.state); + force_gpt_sector = 0; +#endif + return ret; +} From patchwork Fri May 15 01:41:43 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Dmitry Osipenko X-Patchwork-Id: 1290786 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=vger.kernel.org (client-ip=23.128.96.18; helo=vger.kernel.org; envelope-from=linux-tegra-owner@vger.kernel.org; receiver=) Authentication-Results: ozlabs.org; dmarc=pass (p=none dis=none) header.from=gmail.com Authentication-Results: ozlabs.org; dkim=pass (2048-bit key; unprotected) header.d=gmail.com header.i=@gmail.com header.a=rsa-sha256 header.s=20161025 header.b=S57MOdeJ; dkim-atps=neutral Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by ozlabs.org (Postfix) with ESMTP id 49NWQ46BNdz9sTN for ; Fri, 15 May 2020 11:43:08 +1000 (AEST) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1728469AbgEOBnD (ORCPT ); Thu, 14 May 2020 21:43:03 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:55880 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1728407AbgEOBm5 (ORCPT ); Thu, 14 May 2020 21:42:57 -0400 Received: from mail-lj1-x241.google.com (mail-lj1-x241.google.com [IPv6:2a00:1450:4864:20::241]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 9D803C05BD43; Thu, 14 May 2020 18:42:56 -0700 (PDT) Received: by mail-lj1-x241.google.com with SMTP id w10so497769ljo.0; Thu, 14 May 2020 18:42:56 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; bh=DUn2dPZngx4+XjVkOVrsj+EOx6qn7kab4NpjU7rkGDU=; b=S57MOdeJWNH/SagDSDIhyKB8F1fNp8UvWidrmWVjE6NXvFfX6+srdfJLSuA+SPQzIw BcxbxIv2cYXwA2M0OR4Xg2G/LNd1SC3DOIsyhA1C3Rwc8lGlZeiSrbnDaFQtXPoZAwLX 6n7zw+9mbxsSSuoGXXwUQjKKGH7MLy3CUEc1V9f6SVvAcjp6DOEGps+2b99b8WIrgqF5 oASkCanDcSb/o9108BSCIvns8lVgBBH9hHwMQbrQ+JtgMXZ42X58KAqzWNbWrLysQsp7 yzA42EGSSC86eYT8f67fc6deEy09bwvykx8N6tXbw9UQUb6OoRnar24oCPLlpkKS31Z4 bdFQ== 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=DUn2dPZngx4+XjVkOVrsj+EOx6qn7kab4NpjU7rkGDU=; b=pG8zMDnxSs4FKByUY8RuVEJ86ay4XcK48uyR9gBr6XTdW04qn8a1FFTG2hIegSgO4q +aNazwKHfDhak60BoHjhlFYWCCLFqFX0crDVPE6Hug6Q/LLIZq6CKfq+AmaBolzgqbP6 qfcbZi7432qT+fIE9waMCJYFO4AaQ0YYSkqvgB1buJtJzT2lREwCRBOswmLfLQ+pdIQ6 bHVi6d7dJBCzR+LCNrwlCWPHggfRrLAS0BhLNMmZLJ4aQDsY+IypNjPpvZkLAk4kHDfw pM5mhVjYD9zQVjVmEknrqJJ20/2NNo5UdXI5EQS35bALem8BMZdlCHs8reWyQeFPruNW DJhA== X-Gm-Message-State: AOAM532QabBrx9n+XRmqwoIfdFY5tOvDi2ioIPAb//8EtWmd9DtW8uFr 11pRHOozYQGc21PeZkyzGuU= X-Google-Smtp-Source: ABdhPJxLYFQ5GWE8vrtRY7Kg+ry4lzfVCt4sVOa6fo6Fm740HLiGiEo4G9u0053uCnq4n5RdK0IwjA== X-Received: by 2002:a2e:9549:: with SMTP id t9mr624374ljh.283.1589506975025; Thu, 14 May 2020 18:42:55 -0700 (PDT) Received: from localhost.localdomain (ppp91-78-208-152.pppoe.mtu-net.ru. [91.78.208.152]) by smtp.gmail.com with ESMTPSA id i1sm309669lja.3.2020.05.14.18.42.53 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 14 May 2020 18:42:54 -0700 (PDT) From: Dmitry Osipenko To: Jens Axboe , Thierry Reding , Jonathan Hunter , =?utf-8?b?TWljaGHFgiBNaXJvc8WCYXc=?= , David Heidelberg , Peter Geis , Stephen Warren , Nicolas Chauvet , Ulf Hansson , Adrian Hunter , Billy Laws , =?utf-8?q?Nils_=C3=96stlund?= , Christoph Hellwig , Ard Biesheuvel , Davidlohr Bueso Cc: linux-tegra@vger.kernel.org, linux-block@vger.kernel.org, Andrey Danin , Gilles Grandou , Ryan Grachek , linux-mmc@vger.kernel.org, linux-kernel@vger.kernel.org, linux-efi Subject: [PATCH v4 6/6] soc/tegra: Expose Boot Configuration Table via sysfs Date: Fri, 15 May 2020 04:41:43 +0300 Message-Id: <20200515014143.12984-7-digetx@gmail.com> X-Mailer: git-send-email 2.26.0 In-Reply-To: <20200515014143.12984-1-digetx@gmail.com> References: <20200515014143.12984-1-digetx@gmail.com> MIME-Version: 1.0 Sender: linux-tegra-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-tegra@vger.kernel.org It's quite useful to have unencrypted BCT exposed to userspace for debugging purposes, so let's expose it via sysfs. The BCT data will present in /sys/tegra/boot_config_table binary file if BCT is available. Suggested-by: Michał Mirosław Signed-off-by: Dmitry Osipenko --- arch/arm/mach-tegra/tegra.c | 4 +++ drivers/soc/tegra/Makefile | 1 + drivers/soc/tegra/bootdata.c | 51 ++++++++++++++++++++++++++++++++++++ drivers/soc/tegra/common.c | 17 ++++++++++++ include/soc/tegra/bootdata.h | 2 ++ include/soc/tegra/common.h | 3 +++ 6 files changed, 78 insertions(+) create mode 100644 drivers/soc/tegra/bootdata.c diff --git a/arch/arm/mach-tegra/tegra.c b/arch/arm/mach-tegra/tegra.c index da6bcd85398b..5f40463f1b97 100644 --- a/arch/arm/mach-tegra/tegra.c +++ b/arch/arm/mach-tegra/tegra.c @@ -72,6 +72,7 @@ static void __init tegra_boot_config_table_init(void) u32 iram_end = TEGRA_IRAM_BASE + TEGRA_IRAM_SIZE; u32 iram_start = TEGRA_IRAM_BASE; u32 pt_addr, pt_size, bct_size; + void __iomem *bct_ptr; t20_bit = IO_ADDRESS(TEGRA_IRAM_BASE); @@ -90,6 +91,7 @@ static void __init tegra_boot_config_table_init(void) pt_addr = t20_bct->partition_table_logical_sector_address; pt_size = t20_bct->partition_table_num_logical_sectors; + bct_ptr = t20_bct; } else if (of_machine_is_compatible("nvidia,tegra30")) { bct_size = sizeof(*t30_bct); @@ -106,12 +108,14 @@ static void __init tegra_boot_config_table_init(void) pt_addr = t30_bct->partition_table_logical_sector_address; pt_size = t30_bct->partition_table_num_logical_sectors; + bct_ptr = t30_bct; } else { return; } pr_info("%s: BCT found in IRAM\n", __func__); + tegra_bootdata_bct_setup(bct_ptr, bct_size); tegra_partition_table_setup(pt_addr, pt_size); } diff --git a/drivers/soc/tegra/Makefile b/drivers/soc/tegra/Makefile index 9c809c1814bd..8be2bfb4d95d 100644 --- a/drivers/soc/tegra/Makefile +++ b/drivers/soc/tegra/Makefile @@ -1,6 +1,7 @@ # SPDX-License-Identifier: GPL-2.0 obj-y += fuse/ +obj-y += bootdata.o obj-y += common.o obj-$(CONFIG_SOC_TEGRA_FLOWCTRL) += flowctrl.o obj-$(CONFIG_SOC_TEGRA_PMC) += pmc.o diff --git a/drivers/soc/tegra/bootdata.c b/drivers/soc/tegra/bootdata.c new file mode 100644 index 000000000000..e18a27b74023 --- /dev/null +++ b/drivers/soc/tegra/bootdata.c @@ -0,0 +1,51 @@ +// SPDX-License-Identifier: GPL-2.0 + +#include +#include +#include +#include +#include +#include + +#include +#include + +/* + * spare_bct[] will be released once kernel is booted, hence not wasting + * kernel space if BCT is missing. The tegra_bct can't be allocated during + * of BCT setting up because it's too early for the slab allocator. + */ +static u8 spare_bct[SZ_8K] __initdata; +static u8 *tegra_bct; + +static ssize_t boot_config_table_read(struct file *filp, + struct kobject *kobj, + struct bin_attribute *bin_attr, + char *buf, loff_t off, size_t count) +{ + memcpy(buf, tegra_bct + off, count); + return count; +} +static BIN_ATTR_RO(boot_config_table, 0); + +static int __init tegra_bootdata_bct_sysfs_init(void) +{ + if (!bin_attr_boot_config_table.size) + return 0; + + tegra_bct = kmalloc(GFP_KERNEL, bin_attr_boot_config_table.size); + if (!tegra_bct) + return -ENOMEM; + + memcpy(tegra_bct, spare_bct, bin_attr_boot_config_table.size); + + return sysfs_create_bin_file(tegra_soc_kobj, + &bin_attr_boot_config_table); +} +late_initcall(tegra_bootdata_bct_sysfs_init) + +void __init tegra_bootdata_bct_setup(void __iomem *bct_ptr, size_t bct_size) +{ + memcpy_fromio(spare_bct, bct_ptr, bct_size); + bin_attr_boot_config_table.size = bct_size; +} diff --git a/drivers/soc/tegra/common.c b/drivers/soc/tegra/common.c index 3dc54f59cafe..2b4b49eacb2e 100644 --- a/drivers/soc/tegra/common.c +++ b/drivers/soc/tegra/common.c @@ -3,10 +3,15 @@ * Copyright (C) 2014 NVIDIA CORPORATION. All rights reserved. */ +#include +#include #include +#include #include +struct kobject *tegra_soc_kobj; + static const struct of_device_id tegra_machine_match[] = { { .compatible = "nvidia,tegra20", }, { .compatible = "nvidia,tegra30", }, @@ -31,3 +36,15 @@ bool soc_is_tegra(void) return match != NULL; } + +static int __init tegra_soc_sysfs_init(void) +{ + if (!soc_is_tegra()) + return 0; + + tegra_soc_kobj = kobject_create_and_add("tegra", NULL); + WARN_ON(!tegra_soc_kobj); + + return 0; +} +arch_initcall(tegra_soc_sysfs_init) diff --git a/include/soc/tegra/bootdata.h b/include/soc/tegra/bootdata.h index 7be207cb2519..d5c7a251517d 100644 --- a/include/soc/tegra/bootdata.h +++ b/include/soc/tegra/bootdata.h @@ -43,4 +43,6 @@ struct tegra30_boot_config_table { u32 unused_data[3]; } __packed; +void tegra_bootdata_bct_setup(void __iomem *bct_ptr, size_t bct_size); + #endif /* __SOC_TEGRA_BOOTDATA_H__ */ diff --git a/include/soc/tegra/common.h b/include/soc/tegra/common.h index 744280ecab5f..0bc11b45c98e 100644 --- a/include/soc/tegra/common.h +++ b/include/soc/tegra/common.h @@ -7,8 +7,11 @@ #define __SOC_TEGRA_COMMON_H__ #include +#include #ifdef CONFIG_ARCH_TEGRA +extern struct kobject *tegra_soc_kobj; + bool soc_is_tegra(void); #else static inline bool soc_is_tegra(void)