* Re: [PATCH] efi/arm: fix allocation failure when reserving the kernel base
From: Ard Biesheuvel @ 2019-08-21 7:29 UTC (permalink / raw)
To: Mike Rapoport
Cc: Juergen Gross, Joey Lee, linux-efi@vger.kernel.org,
guillaume.gardet@arm.com, linux-kernel@vger.kernel.org,
Russell King - ARM Linux admin, Chester Lin, geert@linux-m68k.org,
ren_guo@c-sky.com, Gary Lin, akpm@linux-foundation.org,
mingo@kernel.org, linux-arm-kernel@lists.infradead.org
In-Reply-To: <20190821071100.GA26713@rapoport-lnx>
On Wed, 21 Aug 2019 at 10:11, Mike Rapoport <rppt@linux.ibm.com> wrote:
>
> On Wed, Aug 21, 2019 at 09:35:16AM +0300, Ard Biesheuvel wrote:
> > On Wed, 21 Aug 2019 at 09:11, Chester Lin <clin@suse.com> wrote:
> > >
> > > On Tue, Aug 20, 2019 at 03:28:25PM +0300, Ard Biesheuvel wrote:
> > > > On Tue, 20 Aug 2019 at 14:56, Russell King - ARM Linux admin
> > > > <linux@armlinux.org.uk> wrote:
> > > > >
> > > > > On Fri, Aug 02, 2019 at 05:38:54AM +0000, Chester Lin wrote:
> > > > > > diff --git a/arch/arm/mm/mmu.c b/arch/arm/mm/mmu.c
> > > > > > index f3ce34113f89..909b11ba48d8 100644
> > > > > > --- a/arch/arm/mm/mmu.c
> > > > > > +++ b/arch/arm/mm/mmu.c
> > > > > > @@ -1184,6 +1184,9 @@ void __init adjust_lowmem_bounds(void)
> > > > > > phys_addr_t block_start = reg->base;
> > > > > > phys_addr_t block_end = reg->base + reg->size;
> > > > > >
> > > > > > + if (memblock_is_nomap(reg))
> > > > > > + continue;
> > > > > > +
> > > > > > if (reg->base < vmalloc_limit) {
> > > > > > if (block_end > lowmem_limit)
> > > > > > /*
> > > > >
> > > > > I think this hunk is sane - if the memory is marked nomap, then it isn't
> > > > > available for the kernel's use, so as far as calculating where the
> > > > > lowmem/highmem boundary is, it effectively doesn't exist and should be
> > > > > skipped.
> > > > >
> > > >
> > > > I agree.
> > > >
> > > > Chester, could you explain what you need beyond this change (and my
> > > > EFI stub change involving TEXT_OFFSET) to make things work on the
> > > > RPi2?
> > > >
> > >
> > > Hi Ard,
> > >
> > > In fact I am working with Guillaume to try booting zImage kernel and openSUSE
> > > from grub2.04 + arm32-efistub so that's why we get this issue on RPi2, which is
> > > one of the test machines we have. However we want a better solution for all
> > > cases but not just RPi2 since we don't want to affect other platforms as well.
> > >
> >
> > Thanks Chester, but that doesn't answer my question.
> >
> > Your fix is a single patch that changes various things that are only
> > vaguely related. We have already identified that we need to take
> > TEXT_OFFSET (minus some space used by the swapper page tables) into
> > account into the EFI stub if we want to ensure compatibility with many
> > different platforms, and as it turns out, this applies not only to
> > RPi2 but to other platforms as well, most notably the ones that
> > require a TEXT_OFFSET of 0x208000, since they also have reserved
> > regions at the base of RAM.
> >
> > My question was what else we need beyond:
> > - the EFI stub TEXT_OFFSET fix [0]
> > - the change to disregard NOMAP memblocks in adjust_lowmem_bounds()
> > - what else???
>
> I think the only missing part here is to ensure that non-reserved memory in
> bank 0 starts from a PMD-aligned address. I believe this could be done if
> EFI stub, but I'm not really familiar with it so this just a semi-educated
> guess :)
>
Given that it is the ARM arch code that imposes this requirement, how
about adding something like this to adjust_lowmem_bounds():
if (memblock_start_of_DRAM() % PMD_SIZE)
memblock_mark_nomap(memblock_start_of_DRAM(),
PMD_SIZE - (memblock_start_of_DRAM() % PMD_SIZE));
(and introduce the nomap check into the loop)
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
^ permalink raw reply
* Re: [PATCH] efi/arm: fix allocation failure when reserving the kernel base
From: Chester Lin @ 2019-08-21 7:22 UTC (permalink / raw)
To: Mike Rapoport
Cc: Juergen Gross, Joey Lee, linux-efi@vger.kernel.org,
guillaume.gardet@arm.com, Ard Biesheuvel,
Russell King - ARM Linux admin, linux-kernel@vger.kernel.org,
Chester Lin, geert@linux-m68k.org, ren_guo@c-sky.com, Gary Lin,
akpm@linux-foundation.org, mingo@kernel.org,
linux-arm-kernel@lists.infradead.org
In-Reply-To: <20190821071100.GA26713@rapoport-lnx>
On Wed, Aug 21, 2019 at 10:11:01AM +0300, Mike Rapoport wrote:
> On Wed, Aug 21, 2019 at 09:35:16AM +0300, Ard Biesheuvel wrote:
> > On Wed, 21 Aug 2019 at 09:11, Chester Lin <clin@suse.com> wrote:
> > >
> > > On Tue, Aug 20, 2019 at 03:28:25PM +0300, Ard Biesheuvel wrote:
> > > > On Tue, 20 Aug 2019 at 14:56, Russell King - ARM Linux admin
> > > > <linux@armlinux.org.uk> wrote:
> > > > >
> > > > > On Fri, Aug 02, 2019 at 05:38:54AM +0000, Chester Lin wrote:
> > > > > > diff --git a/arch/arm/mm/mmu.c b/arch/arm/mm/mmu.c
> > > > > > index f3ce34113f89..909b11ba48d8 100644
> > > > > > --- a/arch/arm/mm/mmu.c
> > > > > > +++ b/arch/arm/mm/mmu.c
> > > > > > @@ -1184,6 +1184,9 @@ void __init adjust_lowmem_bounds(void)
> > > > > > phys_addr_t block_start = reg->base;
> > > > > > phys_addr_t block_end = reg->base + reg->size;
> > > > > >
> > > > > > + if (memblock_is_nomap(reg))
> > > > > > + continue;
> > > > > > +
> > > > > > if (reg->base < vmalloc_limit) {
> > > > > > if (block_end > lowmem_limit)
> > > > > > /*
> > > > >
> > > > > I think this hunk is sane - if the memory is marked nomap, then it isn't
> > > > > available for the kernel's use, so as far as calculating where the
> > > > > lowmem/highmem boundary is, it effectively doesn't exist and should be
> > > > > skipped.
> > > > >
> > > >
> > > > I agree.
> > > >
> > > > Chester, could you explain what you need beyond this change (and my
> > > > EFI stub change involving TEXT_OFFSET) to make things work on the
> > > > RPi2?
> > > >
> > >
> > > Hi Ard,
> > >
> > > In fact I am working with Guillaume to try booting zImage kernel and openSUSE
> > > from grub2.04 + arm32-efistub so that's why we get this issue on RPi2, which is
> > > one of the test machines we have. However we want a better solution for all
> > > cases but not just RPi2 since we don't want to affect other platforms as well.
> > >
> >
> > Thanks Chester, but that doesn't answer my question.
> >
> > Your fix is a single patch that changes various things that are only
> > vaguely related. We have already identified that we need to take
> > TEXT_OFFSET (minus some space used by the swapper page tables) into
> > account into the EFI stub if we want to ensure compatibility with many
> > different platforms, and as it turns out, this applies not only to
> > RPi2 but to other platforms as well, most notably the ones that
> > require a TEXT_OFFSET of 0x208000, since they also have reserved
> > regions at the base of RAM.
> >
> > My question was what else we need beyond:
> > - the EFI stub TEXT_OFFSET fix [0]
> > - the change to disregard NOMAP memblocks in adjust_lowmem_bounds()
> > - what else???
>
> I think the only missing part here is to ensure that non-reserved memory in
> bank 0 starts from a PMD-aligned address. I believe this could be done if
> EFI stub, but I'm not really familiar with it so this just a semi-educated
> guess :)
>
> > [0] https://git.kernel.org/pub/scm/linux/kernel/git/efi/efi.git/commit/?h=next&id=0eb7bad595e52666b642a02862ad996a0f9bfcc0
>
Hi Ard and Mike,
Sorry for my misunderstanding and I agree with Mike. We could still meet the
memblock_limit issue if there's a non-reserved memory in bank0 starts from an
unaligned address.
Regards,
Chester
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
^ permalink raw reply
* Re: [PATCH 6/8] soc: ti: omap_prm: add data for am33xx
From: Tero Kristo @ 2019-08-21 7:23 UTC (permalink / raw)
To: Suman Anna, ssantosh, linux-arm-kernel, linux-omap, robh+dt
Cc: tony, devicetree
In-Reply-To: <ebb6e240-1252-5a4f-39a2-403ee699d8aa@ti.com>
On 20.8.2019 21.48, Suman Anna wrote:
> Hi Tero,
>
> On 8/7/19 2:48 AM, Tero Kristo wrote:
>> Add PRM instance data for AM33xx SoC. Includes some basic register
>> definitions and reset data for now.
>>
>> Signed-off-by: Tero Kristo <t-kristo@ti.com>
>> ---
>> drivers/soc/ti/omap_prm.c | 17 +++++++++++++++++
>> 1 file changed, 17 insertions(+)
>>
>> diff --git a/drivers/soc/ti/omap_prm.c b/drivers/soc/ti/omap_prm.c
>> index 9b8d5945..fadfc7f 100644
>> --- a/drivers/soc/ti/omap_prm.c
>> +++ b/drivers/soc/ti/omap_prm.c
>> @@ -73,8 +73,25 @@ struct omap_prm_data omap4_prm_data[] = {
>> { },
>> };
>>
>> +struct omap_rst_map am3_wkup_rst_map[] = {
>> + { .rst = 3, .st = 5 },
>> + { .rst = -1 },
>> +};
>> +
>> +struct omap_prm_data am3_prm_data[] = {
>> + { .name = "per", .base = 0x44e00c00, .pwstctrl = 0xc, .pwstst = 0x8, .flags = OMAP_PRM_NO_RSTST },
>> + { .name = "wkup", .base = 0x44e00d00, .pwstctrl = 0x4, .pwstst = 0x8, .rstst = 0xc, .rstmap = am3_wkup_rst_map },
>> + { .name = "mpu", .base = 0x44e00e00, .pwstst = 0x4 },
>
> Has a rstst but no rstctrl, but your registration logic takes care of
> this. Somewhat confusing, when you just look at the data. Should you
> limit the check to only rstctrl and OMAP_PRM_NO_RSTST?
I think its probably better I invert the flags and explicitly state
OMAP_PRM_HAS_RSTST | OMAP_PRM_HAS_RSTCTRL, in case any zero value is
used for these.
>
>> + { .name = "device", .base = 0x44e00f00, .rstctl = 0x0, .rstst = 0x8 },
>
> No pwrstctrl and pwrstst registers, so same comment as on OMAP4 data.
I should probably add some flag for this in future once the support for
power domains is added.
Anyway, I'll ditch all pwstctrl / pwstst data for now as it seems to
bother you too much.
-Tero
>
>> + { .name = "rtc", .base = 0x44e01000, .pwstst = 0x4 },
>> + { .name = "gfx", .base = 0x44e01100, .pwstst = 0x10, .rstctl = 0x4, .rstst = 0x14 },
>> + { .name = "cefuse", .base = 0x44e01200, .pwstst = 0x4 },
>
> I am not sure if it is better to explicitly list the registers at 0
> offset rather than using the implied value of 0, since there are some
> registers that do not exist on some PRM instances which are also not
> defined.
>
> regards
> Suman
>
>> + { },
>> +};
>> +
>> static const struct of_device_id omap_prm_id_table[] = {
>> { .compatible = "ti,omap4-prm-inst", .data = omap4_prm_data },
>> + { .compatible = "ti,am3-prm-inst", .data = am3_prm_data },
>> { },
>> };
>>
>>
>
--
Texas Instruments Finland Oy, Porkkalankatu 22, 00180 Helsinki. Y-tunnus/Business ID: 0615521-4. Kotipaikka/Domicile: Helsinki
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
^ permalink raw reply
* [bug report] misc: xilinx_sdfec: Add ability to configure LDPC
From: Dan Carpenter @ 2019-08-21 7:13 UTC (permalink / raw)
To: dragan.cvetic; +Cc: linux-arm-kernel
Hello Dragan Cvetic,
The patch 20ec628e8007: "misc: xilinx_sdfec: Add ability to configure
LDPC" from Jul 27, 2019, leads to the following static checker
warning:
drivers/misc/xilinx_sdfec.c:504 xsdfec_reg1_write()
warn: potential integer overflow from user 'no_packing << (10)'
drivers/misc/xilinx_sdfec.c
492 static int xsdfec_reg1_write(struct xsdfec_dev *xsdfec, u32 psize,
493 u32 no_packing, u32 nm, u32 offset)
494 {
495 u32 wdata;
496
497 if (psize < XSDFEC_REG1_PSIZE_MIN || psize > XSDFEC_REG1_PSIZE_MAX) {
498 dev_dbg(xsdfec->dev, "Psize is not in range");
499 return -EINVAL;
500 }
501
502 if (no_packing != 0 && no_packing != 1)
503 dev_dbg(xsdfec->dev, "No-packing bit register invalid");
Instead of writing invalid data, why not just return -EINVAL?
504 no_packing = ((no_packing << XSDFEC_REG1_NO_PACKING_LSB) &
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Otherwise we have an integer overflow.
505 XSDFEC_REG1_NO_PACKING_MASK);
506
507 if (nm & ~(XSDFEC_REG1_NM_MASK >> XSDFEC_REG1_NM_LSB))
508 dev_dbg(xsdfec->dev, "NM is beyond 10 bits");
509 nm = (nm << XSDFEC_REG1_NM_LSB) & XSDFEC_REG1_NM_MASK;
510
511 wdata = nm | no_packing | psize;
^^^^^^^^^^
When I'm reviewing integer overflow warnings, I look to see if the
variable is re-used after the overflow, and this one is re-used here.
It's probably harmless but it's sort of a pain to review.
512 if (XSDFEC_LDPC_CODE_REG1_ADDR_BASE + (offset * XSDFEC_LDPC_REG_JUMP) >
513 XSDFEC_LDPC_CODE_REG1_ADDR_HIGH) {
514 dev_dbg(xsdfec->dev, "Writing outside of LDPC reg1 space 0x%x",
515 XSDFEC_LDPC_CODE_REG1_ADDR_BASE +
516 (offset * XSDFEC_LDPC_REG_JUMP));
517 return -EINVAL;
518 }
519 xsdfec_regwrite(xsdfec,
520 XSDFEC_LDPC_CODE_REG1_ADDR_BASE +
521 (offset * XSDFEC_LDPC_REG_JUMP),
522 wdata);
523 return 0;
524 }
See also:
drivers/misc/xilinx_sdfec.c:504 xsdfec_reg1_write() warn: potential integer overflow from user 'no_packing << (10)'
drivers/misc/xilinx_sdfec.c:509 xsdfec_reg1_write() warn: potential integer overflow from user 'nm << (11)'
drivers/misc/xilinx_sdfec.c:540 xsdfec_reg2_write() warn: potential integer overflow from user 'nmqc << (9)'
drivers/misc/xilinx_sdfec.c:544 xsdfec_reg2_write() warn: potential integer overflow from user 'norm_type << (20)'
drivers/misc/xilinx_sdfec.c:548 xsdfec_reg2_write() warn: potential integer overflow from user 'special_qc << (21)'
drivers/misc/xilinx_sdfec.c:554 xsdfec_reg2_write() warn: potential integer overflow from user 'no_final_parity << (22)'
drivers/misc/xilinx_sdfec.c:559 xsdfec_reg2_write() warn: potential integer overflow from user 'max_schedule << (23)'
regards,
dan carpenter
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
^ permalink raw reply
* [bug report] misc: xilinx_sdfec: Add ability to configure LDPC
From: Dan Carpenter @ 2019-08-21 7:12 UTC (permalink / raw)
To: dragan.cvetic; +Cc: linux-arm-kernel
Hello Dragan Cvetic,
The patch 20ec628e8007: "misc: xilinx_sdfec: Add ability to configure
LDPC" from Jul 27, 2019, leads to the following static checker
warning:
drivers/misc/xilinx_sdfec.c:727 xsdfec_add_ldpc()
warn: pointer comes from user 'ldpc->la_table'
drivers/misc/xilinx_sdfec.c
647 static int xsdfec_add_ldpc(struct xsdfec_dev *xsdfec, void __user *arg)
648 {
649 struct xsdfec_ldpc_params *ldpc;
650 int ret, n;
651
652 ldpc = kzalloc(sizeof(*ldpc), GFP_KERNEL);
653 if (!ldpc)
654 return -ENOMEM;
655
656 if (copy_from_user(ldpc, arg, sizeof(*ldpc))) {
^^^^
ldpc comes from the user.
657 ret = -EFAULT;
658 goto err_out;
659 }
660
661 if (xsdfec->config.code == XSDFEC_TURBO_CODE) {
662 ret = -EIO;
663 goto err_out;
664 }
665
666 /* Verify Device has not started */
667 if (xsdfec->state == XSDFEC_STARTED) {
668 ret = -EIO;
669 goto err_out;
670 }
671
672 if (xsdfec->config.code_wr_protect) {
673 ret = -EIO;
674 goto err_out;
675 }
676
677 /* Write Reg 0 */
678 ret = xsdfec_reg0_write(xsdfec, ldpc->n, ldpc->k, ldpc->psize,
679 ldpc->code_id);
680 if (ret)
681 goto err_out;
682
683 /* Write Reg 1 */
684 ret = xsdfec_reg1_write(xsdfec, ldpc->psize, ldpc->no_packing, ldpc->nm,
685 ldpc->code_id);
686 if (ret)
687 goto err_out;
688
689 /* Write Reg 2 */
690 ret = xsdfec_reg2_write(xsdfec, ldpc->nlayers, ldpc->nmqc,
691 ldpc->norm_type, ldpc->special_qc,
692 ldpc->no_final_parity, ldpc->max_schedule,
693 ldpc->code_id);
694 if (ret)
695 goto err_out;
696
697 /* Write Reg 3 */
698 ret = xsdfec_reg3_write(xsdfec, ldpc->sc_off, ldpc->la_off,
699 ldpc->qc_off, ldpc->code_id);
700 if (ret)
701 goto err_out;
702
703 /* Write Shared Codes */
704 n = ldpc->nlayers / 4;
705 if (ldpc->nlayers % 4)
706 n++;
707
708 ret = xsdfec_table_write(xsdfec, ldpc->sc_off, ldpc->sc_table, n,
^^^^^^^^^^^^^^
This is not a bug, but it's more like an aesthetic thing. I feel like
->sc_table should be tagged as a __user pointer, but I'm not sure of
the rules exactly. Also the comments say it has to be page aligned but
it will I don't think anyone checks and it should work fine either way
because it just gets rounded down.
709 XSDFEC_LDPC_SC_TABLE_ADDR_BASE,
710 XSDFEC_SC_TABLE_DEPTH);
711 if (ret < 0)
712 goto err_out;
713
714 ret = xsdfec_table_write(xsdfec, 4 * ldpc->la_off, ldpc->la_table,
715 ldpc->nlayers, XSDFEC_LDPC_LA_TABLE_ADDR_BASE,
716 XSDFEC_LA_TABLE_DEPTH);
717 if (ret < 0)
718 goto err_out;
719
720 ret = xsdfec_table_write(xsdfec, 4 * ldpc->qc_off, ldpc->qc_table,
721 ldpc->nqc, XSDFEC_LDPC_QC_TABLE_ADDR_BASE,
722 XSDFEC_QC_TABLE_DEPTH);
723 if (ret > 0)
724 ret = 0;
725 err_out:
726 kfree(ldpc);
727 return ret;
728 }
regards,
dan carpenter
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
^ permalink raw reply
* [PATCH 4/4] misc: xilinx_sdfec: Prevent integer overflow in xsdfec_table_write()
From: Dan Carpenter @ 2019-08-21 7:11 UTC (permalink / raw)
To: Derek Kiernan, Dragan Cvetic
Cc: Arnd Bergmann, Greg Kroah-Hartman, kernel-janitors, Michal Simek,
linux-kernel, linux-arm-kernel
In-Reply-To: <20190821070606.GA26957@mwanda>
The checking here needs to handle integer overflows because "offset" and
"len" come from the user.
Fixes: 20ec628e8007 ("misc: xilinx_sdfec: Add ability to configure LDPC")
Signed-off-by: Dan Carpenter <dan.carpenter@oracle.com>
---
drivers/misc/xilinx_sdfec.c | 4 +++-
1 file changed, 3 insertions(+), 1 deletion(-)
diff --git a/drivers/misc/xilinx_sdfec.c b/drivers/misc/xilinx_sdfec.c
index 3fc53d20abf3..0bf3bcc8e1ef 100644
--- a/drivers/misc/xilinx_sdfec.c
+++ b/drivers/misc/xilinx_sdfec.c
@@ -611,7 +611,9 @@ static int xsdfec_table_write(struct xsdfec_dev *xsdfec, u32 offset,
* Writes that go beyond the length of
* Shared Scale(SC) table should fail
*/
- if ((XSDFEC_REG_WIDTH_JUMP * (offset + len)) > depth) {
+ if (offset > depth / XSDFEC_REG_WIDTH_JUMP ||
+ len > depth / XSDFEC_REG_WIDTH_JUMP ||
+ offset + len > depth / XSDFEC_REG_WIDTH_JUMP) {
dev_dbg(xsdfec->dev, "Write exceeds SC table length");
return -EINVAL;
}
--
2.20.1
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
^ permalink raw reply related
* Re: [PATCH] efi/arm: fix allocation failure when reserving the kernel base
From: Mike Rapoport @ 2019-08-21 7:11 UTC (permalink / raw)
To: Ard Biesheuvel
Cc: Juergen Gross, Joey Lee, linux-efi@vger.kernel.org,
guillaume.gardet@arm.com, linux-kernel@vger.kernel.org,
Russell King - ARM Linux admin, Chester Lin, geert@linux-m68k.org,
ren_guo@c-sky.com, Gary Lin, akpm@linux-foundation.org,
mingo@kernel.org, linux-arm-kernel@lists.infradead.org
In-Reply-To: <CAKv+Gu8Yny8cVPck3rPwCPvJBvcZKMHti_9bkCTM4H4cZ_43fg@mail.gmail.com>
On Wed, Aug 21, 2019 at 09:35:16AM +0300, Ard Biesheuvel wrote:
> On Wed, 21 Aug 2019 at 09:11, Chester Lin <clin@suse.com> wrote:
> >
> > On Tue, Aug 20, 2019 at 03:28:25PM +0300, Ard Biesheuvel wrote:
> > > On Tue, 20 Aug 2019 at 14:56, Russell King - ARM Linux admin
> > > <linux@armlinux.org.uk> wrote:
> > > >
> > > > On Fri, Aug 02, 2019 at 05:38:54AM +0000, Chester Lin wrote:
> > > > > diff --git a/arch/arm/mm/mmu.c b/arch/arm/mm/mmu.c
> > > > > index f3ce34113f89..909b11ba48d8 100644
> > > > > --- a/arch/arm/mm/mmu.c
> > > > > +++ b/arch/arm/mm/mmu.c
> > > > > @@ -1184,6 +1184,9 @@ void __init adjust_lowmem_bounds(void)
> > > > > phys_addr_t block_start = reg->base;
> > > > > phys_addr_t block_end = reg->base + reg->size;
> > > > >
> > > > > + if (memblock_is_nomap(reg))
> > > > > + continue;
> > > > > +
> > > > > if (reg->base < vmalloc_limit) {
> > > > > if (block_end > lowmem_limit)
> > > > > /*
> > > >
> > > > I think this hunk is sane - if the memory is marked nomap, then it isn't
> > > > available for the kernel's use, so as far as calculating where the
> > > > lowmem/highmem boundary is, it effectively doesn't exist and should be
> > > > skipped.
> > > >
> > >
> > > I agree.
> > >
> > > Chester, could you explain what you need beyond this change (and my
> > > EFI stub change involving TEXT_OFFSET) to make things work on the
> > > RPi2?
> > >
> >
> > Hi Ard,
> >
> > In fact I am working with Guillaume to try booting zImage kernel and openSUSE
> > from grub2.04 + arm32-efistub so that's why we get this issue on RPi2, which is
> > one of the test machines we have. However we want a better solution for all
> > cases but not just RPi2 since we don't want to affect other platforms as well.
> >
>
> Thanks Chester, but that doesn't answer my question.
>
> Your fix is a single patch that changes various things that are only
> vaguely related. We have already identified that we need to take
> TEXT_OFFSET (minus some space used by the swapper page tables) into
> account into the EFI stub if we want to ensure compatibility with many
> different platforms, and as it turns out, this applies not only to
> RPi2 but to other platforms as well, most notably the ones that
> require a TEXT_OFFSET of 0x208000, since they also have reserved
> regions at the base of RAM.
>
> My question was what else we need beyond:
> - the EFI stub TEXT_OFFSET fix [0]
> - the change to disregard NOMAP memblocks in adjust_lowmem_bounds()
> - what else???
I think the only missing part here is to ensure that non-reserved memory in
bank 0 starts from a PMD-aligned address. I believe this could be done if
EFI stub, but I'm not really familiar with it so this just a semi-educated
guess :)
> [0] https://git.kernel.org/pub/scm/linux/kernel/git/efi/efi.git/commit/?h=next&id=0eb7bad595e52666b642a02862ad996a0f9bfcc0
--
Sincerely yours,
Mike.
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
^ permalink raw reply
* [PATCH 3/4] misc: xilinx_sdfec: Prevent a divide by zero in xsdfec_reg0_write()
From: Dan Carpenter @ 2019-08-21 7:09 UTC (permalink / raw)
To: Derek Kiernan, Dragan Cvetic
Cc: Arnd Bergmann, Greg Kroah-Hartman, kernel-janitors, Michal Simek,
linux-kernel, linux-arm-kernel
In-Reply-To: <20190821070606.GA26957@mwanda>
The "psize" value comes from the user so we need to verify that it's
non-zero before we check if "n % psize" or it will crash.
Fixes: 20ec628e8007 ("misc: xilinx_sdfec: Add ability to configure LDPC")
Signed-off-by: Dan Carpenter <dan.carpenter@oracle.com>
---
The parentheses in this condition are a no-op. They're just confusing.
Perhaps something else was intended?
drivers/misc/xilinx_sdfec.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/drivers/misc/xilinx_sdfec.c b/drivers/misc/xilinx_sdfec.c
index 813b82c59360..3fc53d20abf3 100644
--- a/drivers/misc/xilinx_sdfec.c
+++ b/drivers/misc/xilinx_sdfec.c
@@ -460,7 +460,7 @@ static int xsdfec_reg0_write(struct xsdfec_dev *xsdfec, u32 n, u32 k, u32 psize,
{
u32 wdata;
- if (n < XSDFEC_REG0_N_MIN || n > XSDFEC_REG0_N_MAX ||
+ if (n < XSDFEC_REG0_N_MIN || n > XSDFEC_REG0_N_MAX || psize == 0 ||
(n > XSDFEC_REG0_N_MUL_P * psize) || n <= k || ((n % psize) != 0)) {
dev_dbg(xsdfec->dev, "N value is not in range");
return -EINVAL;
--
2.20.1
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
^ permalink raw reply related
* [PATCH 2/4] misc: xilinx_sdfec: Return -EFAULT if copy_from_user() fails
From: Dan Carpenter @ 2019-08-21 7:07 UTC (permalink / raw)
To: Derek Kiernan, Dragan Cvetic
Cc: Arnd Bergmann, Greg Kroah-Hartman, kernel-janitors, Michal Simek,
linux-kernel, linux-arm-kernel
In-Reply-To: <20190821070606.GA26957@mwanda>
The copy_from_user() funciton returns the number of bytes remaining to
be copied but we want to return -EFAULT to the user.
Fixes: 20ec628e8007 ("misc: xilinx_sdfec: Add ability to configure LDPC")
Signed-off-by: Dan Carpenter <dan.carpenter@oracle.com>
---
drivers/misc/xilinx_sdfec.c | 5 +++--
1 file changed, 3 insertions(+), 2 deletions(-)
diff --git a/drivers/misc/xilinx_sdfec.c b/drivers/misc/xilinx_sdfec.c
index dc1b8b412712..813b82c59360 100644
--- a/drivers/misc/xilinx_sdfec.c
+++ b/drivers/misc/xilinx_sdfec.c
@@ -651,9 +651,10 @@ static int xsdfec_add_ldpc(struct xsdfec_dev *xsdfec, void __user *arg)
if (!ldpc)
return -ENOMEM;
- ret = copy_from_user(ldpc, arg, sizeof(*ldpc));
- if (ret)
+ if (copy_from_user(ldpc, arg, sizeof(*ldpc))) {
+ ret = -EFAULT;
goto err_out;
+ }
if (xsdfec->config.code == XSDFEC_TURBO_CODE) {
ret = -EIO;
--
2.20.1
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
^ permalink raw reply related
* [PATCH 1/4] misc: xilinx_sdfec: Fix a couple small information leaks
From: Dan Carpenter @ 2019-08-21 7:06 UTC (permalink / raw)
To: Derek Kiernan, Dragan Cvetic
Cc: Arnd Bergmann, Greg Kroah-Hartman, kernel-janitors, Michal Simek,
linux-kernel, linux-arm-kernel
These structs have holes in them so we end up disclosing a few bytes of
uninitialized stack data.
drivers/misc/xilinx_sdfec.c:305 xsdfec_get_status() warn: check that 'status' doesn't leak information (struct has a hole after 'activity')
drivers/misc/xilinx_sdfec.c:449 xsdfec_get_turbo() warn: check that 'turbo_params' doesn't leak information (struct has a hole after 'scale')
We need to zero out the holes with memset().
Fixes: 6bd6a690c2e7 ("misc: xilinx_sdfec: Add stats & status ioctls")
Signed-off-by: Dan Carpenter <dan.carpenter@oracle.com>
---
drivers/misc/xilinx_sdfec.c | 2 ++
1 file changed, 2 insertions(+)
diff --git a/drivers/misc/xilinx_sdfec.c b/drivers/misc/xilinx_sdfec.c
index 912e939dec62..dc1b8b412712 100644
--- a/drivers/misc/xilinx_sdfec.c
+++ b/drivers/misc/xilinx_sdfec.c
@@ -295,6 +295,7 @@ static int xsdfec_get_status(struct xsdfec_dev *xsdfec, void __user *arg)
struct xsdfec_status status;
int err;
+ memset(&status, 0, sizeof(status));
spin_lock_irqsave(&xsdfec->error_data_lock, xsdfec->flags);
status.state = xsdfec->state;
xsdfec->state_updated = false;
@@ -440,6 +441,7 @@ static int xsdfec_get_turbo(struct xsdfec_dev *xsdfec, void __user *arg)
if (xsdfec->config.code == XSDFEC_LDPC_CODE)
return -EIO;
+ memset(&turbo_params, 0, sizeof(turbo_params));
reg_value = xsdfec_regread(xsdfec, XSDFEC_TURBO_ADDR);
turbo_params.scale = (reg_value & XSDFEC_TURBO_SCALE_MASK) >>
--
2.20.1
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
^ permalink raw reply related
* [PATCH 9/9] fs: f2fs: support diskcipher
From: boojin.kim @ 2019-08-21 6:42 UTC (permalink / raw)
To: 'Jaegeuk Kim', 'Chao Yu', linux-f2fs-devel,
linux-kernel, linux-fsdevel
Cc: 'Ulf Hansson', 'Mike Snitzer', dm-devel,
'Andreas Dilger', 'Alasdair Kergon',
'Eric Biggers', linux-samsung-soc, 'Herbert Xu',
'Krzysztof Kozlowski', 'Jaehoon Chung',
'Kukjin Kim', linux-ext4, 'Chao Yu', linux-block,
linux-fscrypt, 'Jaegeuk Kim', linux-arm-kernel,
'Jens Axboe', 'Theodore Ts'o', linux-mmc,
linux-kernel, linux-f2fs-devel, linux-crypto, linux-fsdevel,
'David S. Miller'
In-Reply-To: <CGME20190821064244epcas2p1e3d77667eed99670611d9353cf365f8b@epcas2p1.samsung.com>
F2FS checks the crypto properties of the inode, and if it is a diskcipher,
sets it to BIO before submitting the BIO.
When using diskcipher, F2FS does not encrypt the data before submitting
the bio and decrypt the data on complete of the BIO.
F2FS uses DUN(device unit number) as the IV(initial vector)
for cryptographic operations.
DUN can support the Garbage collection of f2fs.
Even if a data is moved in the storage device by garbage collection,
the data has same DUN, so that the data can be decrypted.
F2FS calculates DUN of data and sets it to BIO.
Cc: Jaegeuk Kim <jaegeuk@kernel.org>
Cc: Chao Yu <chao@kernel.org>
Signed-off-by: Boojin Kim <boojin.kim@samsung.com>
---
fs/f2fs/data.c | 98
++++++++++++++++++++++++++++++++++++++++++++++++++++++++--
fs/f2fs/f2fs.h | 2 +-
2 files changed, 97 insertions(+), 3 deletions(-)
diff --git a/fs/f2fs/data.c b/fs/f2fs/data.c
index 3dfefab..c8252bf 100644
--- a/fs/f2fs/data.c
+++ b/fs/f2fs/data.c
@@ -85,6 +85,52 @@ struct bio_post_read_ctx {
unsigned int enabled_steps;
};
+/* device unit number for iv sector */
+#define PG_DUN(i, p) \
+ ((((i)->i_ino & 0xffffffff) << 32) | (p & 0xffffffff))
+
+static inline bool f2fs_may_encrypt_bio(struct inode *inode,
+ struct f2fs_io_info *fio)
+{
+#ifdef CONFIG_CRYPTO_DISKCIPHER
+ if (fio && (fio->type != DATA || fio->encrypted_page))
+ return false;
+
+ return (f2fs_encrypted_file(inode) &&
+ fscrypt_disk_encrypted(inode));
+#else
+ return false;
+#endif
+}
+
+static inline bool f2fs_bio_disk_encrypted(unsigned int bi_opf)
+{
+ if (bi_opf & REQ_CRYPT)
+ return true;
+ else
+ return false;
+}
+
+static bool f2fs_mergeable_bio(struct bio *bio, u64 dun, void *ci,
+ bool bio_encrypted)
+{
+#ifdef CONFIG_CRYPTO_DISKCIPHER
+ if (!bio)
+ return true;
+
+ /* if both of them are not encrypted, no further check is needed */
+ if (!f2fs_bio_disk_encrypted(bio->bi_opf) && !bio_encrypted)
+ return true;
+
+ if (bio->bi_aux_private == ci)
+ return bio_end_dun(bio) == dun;
+ else
+ return false;
+#else
+ return true;
+#endif
+}
+
static void __read_end_io(struct bio *bio)
{
struct page *page;
@@ -174,6 +220,9 @@ static void f2fs_read_end_io(struct bio *bio)
bio->bi_status = BLK_STS_IOERR;
}
+ if (f2fs_bio_disk_encrypted(bio->bi_opf))
+ goto end_io;
+
if (f2fs_bio_post_read_required(bio)) {
struct bio_post_read_ctx *ctx = bio->bi_private;
@@ -182,6 +231,7 @@ static void f2fs_read_end_io(struct bio *bio)
return;
}
+end_io:
__read_end_io(bio);
}
@@ -362,7 +412,10 @@ static void __submit_merged_bio(struct f2fs_bio_info
*io)
if (!io->bio)
return;
- bio_set_op_attrs(io->bio, fio->op, fio->op_flags);
+ if (f2fs_bio_disk_encrypted(io->bio->bi_opf))
+ bio_set_op_attrs(io->bio, fio->op, fio->op_flags |
REQ_CRYPT);
+ else
+ bio_set_op_attrs(io->bio, fio->op, fio->op_flags);
if (is_read_io(fio->op))
trace_f2fs_prepare_read_bio(io->sbi->sb, fio->type,
io->bio);
@@ -476,6 +529,7 @@ int f2fs_submit_page_bio(struct f2fs_io_info *fio)
struct bio *bio;
struct page *page = fio->encrypted_page ?
fio->encrypted_page : fio->page;
+ struct inode *inode = fio->page->mapping->host;
if (!f2fs_is_valid_blkaddr(fio->sbi, fio->new_blkaddr,
fio->is_por ? META_POR : (__is_meta_io(fio) ?
@@ -502,6 +556,9 @@ int f2fs_submit_page_bio(struct f2fs_io_info *fio)
inc_page_count(fio->sbi, is_read_io(fio->op) ?
__read_io_type(page): WB_DATA_TYPE(fio->page));
+ if (f2fs_may_encrypt_bio(inode, fio))
+ fscrypt_set_bio(inode, bio, PG_DUN(inode,
fio->page->index));
+
__submit_bio(fio->sbi, bio, fio->type);
return 0;
}
@@ -604,6 +661,9 @@ void f2fs_submit_page_write(struct f2fs_io_info *fio)
enum page_type btype = PAGE_TYPE_OF_BIO(fio->type);
struct f2fs_bio_info *io = sbi->write_io[btype] + fio->temp;
struct page *bio_page;
+ struct inode *inode;
+ bool bio_encrypted;
+ u64 dun;
f2fs_bug_on(sbi, is_read_io(fio->op));
@@ -624,6 +684,9 @@ void f2fs_submit_page_write(struct f2fs_io_info *fio)
verify_fio_blkaddr(fio);
bio_page = fio->encrypted_page ? fio->encrypted_page : fio->page;
+ inode = fio->page->mapping->host;
+ dun = PG_DUN(inode, fio->page->index);
+ bio_encrypted = f2fs_may_encrypt_bio(inode, fio);
/* set submitted = true as a return value */
fio->submitted = true;
@@ -633,6 +696,10 @@ void f2fs_submit_page_write(struct f2fs_io_info *fio)
if (io->bio && !io_is_mergeable(sbi, io->bio, io, fio,
io->last_block_in_bio, fio->new_blkaddr))
__submit_merged_bio(io);
+
+ if (!f2fs_mergeable_bio(io->bio, dun,
+ fscrypt_get_diskcipher(inode), bio_encrypted))
+ __submit_merged_bio(io);
alloc_new:
if (io->bio == NULL) {
if ((fio->type == DATA || fio->type == NODE) &&
@@ -644,6 +711,9 @@ void f2fs_submit_page_write(struct f2fs_io_info *fio)
io->bio = __bio_alloc(sbi, fio->new_blkaddr, fio->io_wbc,
BIO_MAX_PAGES, false,
fio->type, fio->temp);
+ if (bio_encrypted)
+ fscrypt_set_bio(inode, io->bio, dun);
+
io->fio = *fio;
}
@@ -691,7 +761,7 @@ static struct bio *f2fs_grab_read_bio(struct inode
*inode, block_t blkaddr,
bio->bi_end_io = f2fs_read_end_io;
bio_set_op_attrs(bio, REQ_OP_READ, op_flag);
- if (f2fs_encrypted_file(inode))
+ if (f2fs_encrypted_file(inode) && !fscrypt_disk_encrypted(inode))
post_read_steps |= 1 << STEP_DECRYPT;
if (f2fs_need_verity(inode, first_idx))
@@ -731,6 +801,10 @@ static int f2fs_submit_page_read(struct inode *inode,
struct page *page,
}
ClearPageError(page);
inc_page_count(sbi, F2FS_RD_DATA);
+
+ if (f2fs_may_encrypt_bio(inode, NULL))
+ fscrypt_set_bio(inode, bio, PG_DUN(inode, page->index));
+
__submit_bio(sbi, bio, DATA);
return 0;
}
@@ -1665,6 +1739,8 @@ static int f2fs_read_single_page(struct inode *inode,
struct page *page,
sector_t last_block_in_file;
sector_t block_nr;
int ret = 0;
+ bool bio_encrypted;
+ u64 dun;
block_in_file = (sector_t)page_index(page);
last_block = block_in_file + nr_pages;
@@ -1734,6 +1810,15 @@ static int f2fs_read_single_page(struct inode *inode,
struct page *page,
__submit_bio(F2FS_I_SB(inode), bio, DATA);
bio = NULL;
}
+
+ dun = PG_DUN(inode, page->index);
+ bio_encrypted = f2fs_may_encrypt_bio(inode, NULL);
+ if (!f2fs_mergeable_bio(bio, dun, fscrypt_get_diskcipher(inode),
+ bio_encrypted)) {
+ __submit_bio(F2FS_I_SB(inode), bio, DATA);
+ bio = NULL;
+ }
+
if (bio == NULL) {
bio = f2fs_grab_read_bio(inode, block_nr, nr_pages,
is_readahead ? REQ_RAHEAD : 0, page->index);
@@ -1742,6 +1827,8 @@ static int f2fs_read_single_page(struct inode *inode,
struct page *page,
bio = NULL;
goto out;
}
+ if (f2fs_may_encrypt_bio(inode, NULL))
+ fscrypt_set_bio(inode, bio, dun);
}
/*
@@ -1870,6 +1957,9 @@ static int encrypt_one_page(struct f2fs_io_info *fio)
f2fs_wait_on_block_writeback(inode, fio->old_blkaddr);
retry_encrypt:
+ if (fscrypt_disk_encrypted(inode))
+ return 0;
+
fio->encrypted_page = fscrypt_encrypt_pagecache_blocks(fio->page,
PAGE_SIZE, 0,
gfp_flags);
@@ -2804,6 +2894,10 @@ static void f2fs_dio_submit_bio(struct bio *bio,
struct inode *inode,
if (!dio)
goto out;
+ if (dio->inode && fscrypt_has_encryption_key(dio->inode))
+ fscrypt_set_bio(inode, bio, PG_DUN(inode,
+ file_offset >> PAGE_SHIFT));
+
dio->inode = inode;
dio->orig_end_io = bio->bi_end_io;
dio->orig_private = bio->bi_private;
diff --git a/fs/f2fs/f2fs.h b/fs/f2fs/f2fs.h
index 0cbf1d4..8447542 100644
--- a/fs/f2fs/f2fs.h
+++ b/fs/f2fs/f2fs.h
@@ -3706,7 +3706,7 @@ static inline bool f2fs_force_buffered_io(struct inode
*inode,
struct f2fs_sb_info *sbi = F2FS_I_SB(inode);
int rw = iov_iter_rw(iter);
- if (f2fs_post_read_required(inode))
+ if (f2fs_post_read_required(inode) &&
!fscrypt_disk_encrypted(inode))
return true;
if (f2fs_is_multi_device(sbi))
return true;
--
2.7.4
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
^ permalink raw reply related
* [PATCH 7/9] fscrypt: support diskcipher
From: boojin.kim @ 2019-08-21 6:42 UTC (permalink / raw)
To: 'Theodore Y. Ts'o', 'Jaegeuk Kim',
'Eric Biggers', linux-fscrypt, linux-kernel,
linux-fsdevel
Cc: 'Ulf Hansson', 'Mike Snitzer', dm-devel,
'Andreas Dilger', 'Alasdair Kergon',
'Eric Biggers', linux-samsung-soc, 'Herbert Xu',
'Krzysztof Kozlowski', 'Jaehoon Chung',
'Kukjin Kim', linux-ext4, 'Chao Yu', linux-block,
linux-fscrypt, 'Jaegeuk Kim', linux-arm-kernel,
'Jens Axboe', 'Theodore Ts'o', linux-mmc,
linux-kernel, linux-f2fs-devel, linux-crypto, linux-fsdevel,
'David S. Miller'
In-Reply-To: <CGME20190821064237epcas2p4d8bc4858fda55be213eb51b19e52fc71@epcas2p4.samsung.com>
This patch support fscrypt to use diskcipher in a specific crypto mode
(FSCRYPT_MODE_PRIVATE).
Fscrypt allocates diskcipher and sets the key on diskcipher.
Fscrypt doesn't handle additional data encryption when using diskcipher.
Cc: Theodore Y. Ts'o <tytso@mit.edu>
Cc: Jaegeuk Kim <jaegeuk@kernel.org>
Cc: Eric Biggers <ebiggers@kernel.org>
Signed-off-by: Boojin Kim <boojin.kim@samsung.com>
---
fs/buffer.c | 2 ++
fs/crypto/bio.c | 43 ++++++++++++++++++++++++++-----
fs/crypto/fscrypt_private.h | 28 +++++++++++++++++++-
fs/crypto/keysetup.c | 60
+++++++++++++++++++++++++++++++++++++++++--
fs/crypto/keysetup_v1.c | 2 +-
include/linux/fscrypt.h | 19 ++++++++++++++
include/uapi/linux/fscrypt.h | 2 ++
tools/include/uapi/linux/fs.h | 1 +
8 files changed, 147 insertions(+), 10 deletions(-)
diff --git a/fs/buffer.c b/fs/buffer.c
index 131d39e..a7de079 100644
--- a/fs/buffer.c
+++ b/fs/buffer.c
@@ -3129,6 +3129,8 @@ static int submit_bh_wbc(int op, int op_flags, struct
buffer_head *bh,
wbc_account_cgroup_owner(wbc, bh->b_page, bh->b_size);
}
+ if (bio->bi_opf & REQ_CRYPT)
+ bio->bi_aux_private = bh->b_private;
submit_bio(bio);
return 0;
}
diff --git a/fs/crypto/bio.c b/fs/crypto/bio.c
index 82da251..9e4bf9b 100644
--- a/fs/crypto/bio.c
+++ b/fs/crypto/bio.c
@@ -24,6 +24,7 @@
#include <linux/module.h>
#include <linux/bio.h>
#include <linux/namei.h>
+#include <crypto/diskcipher.h>
#include "fscrypt_private.h"
static void __fscrypt_decrypt_bio(struct bio *bio, bool done)
@@ -81,13 +82,19 @@ int fscrypt_zeroout_range(const struct inode *inode,
pgoff_t lblk,
if (!ciphertext_page)
return -ENOMEM;
- while (len--) {
- err = fscrypt_crypt_block(inode, FS_ENCRYPT, lblk,
- ZERO_PAGE(0), ciphertext_page,
- blocksize, 0, GFP_NOFS);
- if (err)
- goto errout;
+ if (__fscrypt_disk_encrypted(inode)) {
+ memset(page_address(ciphertext_page), 0, PAGE_SIZE);
+ ciphertext_page->mapping = inode->i_mapping;
+ }
+ while (len--) {
+ if (!__fscrypt_disk_encrypted(inode)) {
+ err = fscrypt_crypt_block(inode, FS_ENCRYPT, lblk,
+ ZERO_PAGE(0),
ciphertext_page,
+ blocksize, 0, GFP_NOFS);
+ if (err)
+ goto errout;
+ }
bio = bio_alloc(GFP_NOWAIT, 1);
if (!bio) {
err = -ENOMEM;
@@ -103,6 +110,7 @@ int fscrypt_zeroout_range(const struct inode *inode,
pgoff_t lblk,
err = -EIO;
goto errout;
}
+ fscrypt_set_bio(inode, bio, 0);
err = submit_bio_wait(bio);
if (err == 0 && bio->bi_status)
err = -EIO;
@@ -118,3 +126,26 @@ int fscrypt_zeroout_range(const struct inode *inode,
pgoff_t lblk,
return err;
}
EXPORT_SYMBOL(fscrypt_zeroout_range);
+
+int fscrypt_disk_encrypted(const struct inode *inode)
+{
+ return __fscrypt_disk_encrypted(inode);
+}
+
+void fscrypt_set_bio(const struct inode *inode, struct bio *bio, u64 dun)
+{
+#ifdef CONFIG_CRYPTO_DISKCIPHER
+ if (__fscrypt_disk_encrypted(inode))
+ crypto_diskcipher_set(bio, inode->i_crypt_info->ci_dtfm,
+ inode, dun);
+#endif
+}
+
+void *fscrypt_get_diskcipher(const struct inode *inode)
+{
+#ifdef CONFIG_CRYPTO_DISKCIPHER
+ if (fscrypt_has_encryption_key(inode))
+ return inode->i_crypt_info->ci_dtfm;
+#endif
+ return NULL;
+}
diff --git a/fs/crypto/fscrypt_private.h b/fs/crypto/fscrypt_private.h
index e84efc0..d2b5fb6 100644
--- a/fs/crypto/fscrypt_private.h
+++ b/fs/crypto/fscrypt_private.h
@@ -163,6 +163,10 @@ struct fscrypt_info {
/* The actual crypto transform used for encryption and decryption */
struct crypto_skcipher *ci_ctfm;
+ /* Cipher for inline encryption engine */
+#ifdef CONFIG_CRYPTO_DISKCIPHER
+ struct crypto_diskcipher *ci_dtfm;
+#endif
/*
* Cipher for ESSIV IV generation. Only set for CBC contents
* encryption, otherwise is NULL.
@@ -226,6 +230,10 @@ static inline bool fscrypt_valid_enc_modes(u32
contents_mode,
filenames_mode == FSCRYPT_MODE_ADIANTUM)
return true;
+ if (contents_mode == FSCRYPT_MODE_PRIVATE &&
+ filenames_mode == FSCRYPT_MODE_AES_256_CTS)
+ return true;
+
return false;
}
@@ -438,13 +446,19 @@ extern int __init fscrypt_init_keyring(void);
/* keysetup.c */
+enum cipher_flags {
+ CRYPT_MODE_SKCIPHER,
+ CRYPT_MODE_ESSIV,
+ CRYPT_MODE_DISKCIPHER,
+};
+
struct fscrypt_mode {
const char *friendly_name;
const char *cipher_str;
int keysize;
int ivsize;
bool logged_impl_name;
- bool needs_essiv;
+ enum cipher_flags flags;
};
static inline bool
@@ -453,6 +467,18 @@ fscrypt_mode_supports_direct_key(const struct
fscrypt_mode *mode)
return mode->ivsize >= offsetofend(union fscrypt_iv, nonce);
}
+static inline int __fscrypt_disk_encrypted(const struct inode *inode)
+{
+#if IS_ENABLED(CONFIG_FS_ENCRYPTION)
+#if IS_ENABLED(CONFIG_CRYPTO_DISKCIPHER)
+ if (inode && inode->i_crypt_info)
+ return S_ISREG(inode->i_mode) &&
+ (inode->i_crypt_info->ci_dtfm != NULL);
+#endif
+#endif
+ return 0;
+}
+
extern struct crypto_skcipher *
fscrypt_allocate_skcipher(struct fscrypt_mode *mode, const u8 *raw_key,
const struct inode *inode);
diff --git a/fs/crypto/keysetup.c b/fs/crypto/keysetup.c
index d71c2d6..06d9609 100644
--- a/fs/crypto/keysetup.c
+++ b/fs/crypto/keysetup.c
@@ -11,6 +11,7 @@
#include <crypto/aes.h>
#include <crypto/sha.h>
#include <crypto/skcipher.h>
+#include <crypto/diskcipher.h>
#include <linux/key.h>
#include "fscrypt_private.h"
@@ -35,7 +36,7 @@ static struct fscrypt_mode available_modes[] = {
.cipher_str = "cbc(aes)",
.keysize = 16,
.ivsize = 16,
- .needs_essiv = true,
+ .flags = CRYPT_MODE_ESSIV,
},
[FSCRYPT_MODE_AES_128_CTS] = {
.friendly_name = "AES-128-CTS-CBC",
@@ -49,6 +50,13 @@ static struct fscrypt_mode available_modes[] = {
.keysize = 32,
.ivsize = 32,
},
+ [FSCRYPT_MODE_PRIVATE] = {
+ .friendly_name = "AES-256-XTS-DISK",
+ .cipher_str = "xts(aes)-disk",
+ .keysize = 64,
+ .ivsize = 16,
+ .flags = CRYPT_MODE_DISKCIPHER,
+ },
};
static struct fscrypt_mode *
@@ -111,6 +119,35 @@ struct crypto_skcipher
*fscrypt_allocate_skcipher(struct fscrypt_mode *mode,
return ERR_PTR(err);
}
+#if defined(CONFIG_CRYPTO_DISKCIPHER)
+/* Create a diskcipher cipher object for the given encryption mode and key
*/
+static struct crypto_diskcipher *fscrypt_allocate_diskcipher(
+ struct fscrypt_mode *mode, const u8 *raw_key,
+ const struct inode *inode)
+{
+ struct crypto_diskcipher *tfm;
+ int err;
+ bool force = (mode->flags == CRYPT_MODE_DISKCIPHER) ? 0 : 1;
+
+ tfm = crypto_alloc_diskcipher(mode->cipher_str, 0, 0, force);
+ if (IS_ERR(tfm)) {
+ fscrypt_warn(inode->i_sb,
+ "error allocating '%s' transform for inode
%lu: %ld",
+ mode->cipher_str, inode->i_ino,
PTR_ERR(tfm));
+ return tfm;
+ }
+ err = crypto_diskcipher_setkey(tfm, raw_key, mode->keysize, 0);
+ if (err)
+ goto err_free_dtfm;
+
+ return tfm;
+
+err_free_dtfm:
+ crypto_free_diskcipher(tfm);
+ return ERR_PTR(err);
+}
+#endif
+
static int derive_essiv_salt(const u8 *key, int keysize, u8 *salt)
{
struct crypto_shash *tfm = READ_ONCE(essiv_hash_tfm);
@@ -187,13 +224,29 @@ int fscrypt_set_derived_key(struct fscrypt_info *ci,
const u8 *derived_key)
struct crypto_skcipher *ctfm;
int err;
+#if defined(CONFIG_CRYPTO_DISKCIPHER)
+ if (S_ISREG(ci->ci_inode->i_mode) &&
+ (mode->flags == CRYPT_MODE_DISKCIPHER)) {
+ ci->ci_dtfm = fscrypt_allocate_diskcipher(mode, derived_key,
+
ci->ci_inode);
+ if (IS_ERR(ci->ci_dtfm)) {
+ fscrypt_warn(ci->ci_inode,
+ "Error allocating Diskcipher: %p",
+ PTR_ERR(ci->ci_dtfm));
+ ci->ci_dtfm = NULL;
+ return -EINVAL;
+ }
+ return 0;
+ }
+#endif
+
ctfm = fscrypt_allocate_skcipher(mode, derived_key, ci->ci_inode);
if (IS_ERR(ctfm))
return PTR_ERR(ctfm);
ci->ci_ctfm = ctfm;
- if (mode->needs_essiv) {
+ if (mode->flags == CRYPT_MODE_ESSIV) {
err = init_essiv_generator(ci, derived_key, mode->keysize);
if (err) {
fscrypt_warn(ci->ci_inode,
@@ -394,6 +447,9 @@ static void put_crypt_info(struct fscrypt_info *ci)
!fscrypt_is_direct_key_policy(&ci->ci_policy)) {
crypto_free_skcipher(ci->ci_ctfm);
crypto_free_cipher(ci->ci_essiv_tfm);
+#if defined(CONFIG_CRYPTO_DISKCIPHER)
+ crypto_free_diskcipher(ci->ci_dtfm);
+#endif
}
key = ci->ci_master_key;
diff --git a/fs/crypto/keysetup_v1.c b/fs/crypto/keysetup_v1.c
index 0727251..22d0330 100644
--- a/fs/crypto/keysetup_v1.c
+++ b/fs/crypto/keysetup_v1.c
@@ -271,7 +271,7 @@ static int setup_v1_file_key_direct(struct fscrypt_info
*ci,
}
/* ESSIV implies 16-byte IVs which implies !DIRECT_KEY */
- if (WARN_ON(mode->needs_essiv))
+ if (WARN_ON(mode->flags == CRYPT_MODE_ESSIV))
return -EINVAL;
dk = fscrypt_get_direct_key(ci, raw_master_key);
diff --git a/include/linux/fscrypt.h b/include/linux/fscrypt.h
index f622f74..e0f99db 100644
--- a/include/linux/fscrypt.h
+++ b/include/linux/fscrypt.h
@@ -274,6 +274,11 @@ static inline void fscrypt_set_ops(struct super_block
*sb,
{
sb->s_cop = s_cop;
}
+
+void fscrypt_set_bio(const struct inode *inode, struct bio *bio, u64 dun);
+void *fscrypt_get_diskcipher(const struct inode *inode);
+int fscrypt_disk_encrypted(const struct inode *inode);
+
#else /* !CONFIG_FS_ENCRYPTION */
static inline bool fscrypt_has_encryption_key(const struct inode *inode)
@@ -556,6 +561,20 @@ static inline void fscrypt_set_ops(struct super_block
*sb,
{
}
+static inline int fscrypt_disk_encrypted(const struct inode *inode)
+{
+ return 0;
+}
+
+static inline void fscrypt_set_bio(const struct inode *inode,
+ struct bio *bio, u64 dun)
+{
+}
+
+static inline void *fscrypt_get_diskcipher(const struct inode *inode)
+{
+ return NULL;
+}
#endif /* !CONFIG_FS_ENCRYPTION */
/**
diff --git a/include/uapi/linux/fscrypt.h b/include/uapi/linux/fscrypt.h
index 39ccfe9..b9978c4 100644
--- a/include/uapi/linux/fscrypt.h
+++ b/include/uapi/linux/fscrypt.h
@@ -25,6 +25,7 @@
#define FSCRYPT_MODE_AES_128_CBC 5
#define FSCRYPT_MODE_AES_128_CTS 6
#define FSCRYPT_MODE_ADIANTUM 9
+#define FSCRYPT_MODE_PRIVATE 127
#define __FSCRYPT_MODE_MAX 9
/*
@@ -173,6 +174,7 @@ struct fscrypt_get_key_status_arg {
#define FS_ENCRYPTION_MODE_SPECK128_256_XTS 7 /* removed */
#define FS_ENCRYPTION_MODE_SPECK128_256_CTS 8 /* removed */
#define FS_ENCRYPTION_MODE_ADIANTUM FSCRYPT_MODE_ADIANTUM
+#define FS_ENCRYPTION_MODE_PRIVATE FSCRYPT_MODE_PRIVATE
#define FS_KEY_DESC_PREFIX FSCRYPT_KEY_DESC_PREFIX
#define FS_KEY_DESC_PREFIX_SIZE FSCRYPT_KEY_DESC_PREFIX_SIZE
#define FS_MAX_KEY_SIZE FSCRYPT_MAX_KEY_SIZE
diff --git a/tools/include/uapi/linux/fs.h b/tools/include/uapi/linux/fs.h
index 2a616aa..dd3566a 100644
--- a/tools/include/uapi/linux/fs.h
+++ b/tools/include/uapi/linux/fs.h
@@ -237,6 +237,7 @@ struct fsxattr {
#define FS_ENCRYPTION_MODE_SPECK128_256_XTS 7 /* Removed, do not use. */
#define FS_ENCRYPTION_MODE_SPECK128_256_CTS 8 /* Removed, do not use. */
#define FS_ENCRYPTION_MODE_ADIANTUM 9
+#define FS_ENCRYPTION_MODE_PRIVATE 127
struct fscrypt_policy {
__u8 version;
--
2.7.4
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
^ permalink raw reply related
* [PATCH 8/9] fs: ext4: support diskcipher
From: boojin.kim @ 2019-08-21 6:42 UTC (permalink / raw)
To: 'Theodore Ts'o', 'Andreas Dilger', linux-ext4,
linux-kernel, linux-fsdevel
Cc: 'Ulf Hansson', 'Mike Snitzer', dm-devel,
'Andreas Dilger', 'Alasdair Kergon',
'Eric Biggers', linux-samsung-soc, 'Herbert Xu',
'Krzysztof Kozlowski', 'Jaehoon Chung',
'Kukjin Kim', linux-ext4, 'Chao Yu', linux-block,
linux-fscrypt, 'Jaegeuk Kim', linux-arm-kernel,
'Jens Axboe', 'Theodore Ts'o', linux-mmc,
linux-kernel, linux-f2fs-devel, linux-crypto, linux-fsdevel,
'David S. Miller'
In-Reply-To: <CGME20190821064241epcas2p2bf71ad8055188f8b47870b06480c8368@epcas2p2.samsung.com>
Ext4 checks the crypto properties of the inode,
and if it is a diskcipher, sets it to BIO before submitting the BIO.
When using diskcipher, Ext4 does not encrypt the data before submitting
the BIO and decrypt the data on complete of the BIO.
Cc: Theodore Ts'o <tytso@mit.edu>
Cc: Andreas Dilger <adilger.kernel@dilger.ca>
Signed-off-by: Boojin Kim <boojin.kim@samsung.com>
---
fs/ext4/inode.c | 39 +++++++++++++++++++++++++++++++++------
fs/ext4/page-io.c | 8 +++++++-
fs/ext4/readpage.c | 7 +++++++
3 files changed, 47 insertions(+), 7 deletions(-)
diff --git a/fs/ext4/inode.c b/fs/ext4/inode.c
index 5bcc96f..7f9e1fa 100644
--- a/fs/ext4/inode.c
+++ b/fs/ext4/inode.c
@@ -1223,7 +1223,14 @@ static int ext4_block_write_begin(struct page *page,
loff_t pos, unsigned len,
if (!buffer_uptodate(bh) && !buffer_delay(bh) &&
!buffer_unwritten(bh) &&
(block_start < from || block_end > to)) {
- ll_rw_block(REQ_OP_READ, 0, 1, &bh);
+ if (S_ISREG(inode->i_mode) && IS_ENCRYPTED(inode)
+ &&
fscrypt_has_encryption_key(inode)) {
+ bh->b_private =
fscrypt_get_diskcipher(inode);
+ ll_rw_block(REQ_OP_READ,
+ bh->b_private ? REQ_CRYPT : 0, 1,
&bh);
+ } else {
+ ll_rw_block(REQ_OP_READ, 0, 1, &bh);
+ }
wait[nr_wait++] = bh;
}
}
@@ -1237,7 +1244,8 @@ static int ext4_block_write_begin(struct page *page,
loff_t pos, unsigned len,
}
if (unlikely(err)) {
page_zero_new_buffers(page, from, to);
- } else if (IS_ENCRYPTED(inode) && S_ISREG(inode->i_mode)) {
+ } else if (IS_ENCRYPTED(inode) && S_ISREG(inode->i_mode) &&
+ !bh->b_private) {
for (i = 0; i < nr_wait; i++) {
int err2;
@@ -3670,6 +3678,13 @@ const struct iomap_ops ext4_iomap_ops = {
.iomap_end = ext4_iomap_end,
};
+static void ext4_submit_dio(struct bio *bio, struct inode *inode,
+ loff_t file_offset)
+{
+ fscrypt_set_bio(inode, bio, 0);
+ submit_bio(bio);
+}
+
static int ext4_end_io_dio(struct kiocb *iocb, loff_t offset,
ssize_t size, void *private)
{
@@ -3801,7 +3816,9 @@ static ssize_t ext4_direct_IO_write(struct kiocb
*iocb, struct iov_iter *iter)
dio_flags = DIO_LOCKING;
}
ret = __blockdev_direct_IO(iocb, inode, inode->i_sb->s_bdev, iter,
- get_block_func, ext4_end_io_dio, NULL,
+ get_block_func, ext4_end_io_dio,
+ !fscrypt_disk_encrypted(inode) ?
+ NULL : ext4_submit_dio,
dio_flags);
if (ret > 0 && !overwrite && ext4_test_inode_state(inode,
@@ -3909,7 +3926,8 @@ static ssize_t ext4_direct_IO(struct kiocb *iocb,
struct iov_iter *iter)
ssize_t ret;
#ifdef CONFIG_FS_ENCRYPTION
- if (IS_ENCRYPTED(inode) && S_ISREG(inode->i_mode))
+ if (IS_ENCRYPTED(inode) && S_ISREG(inode->i_mode)
+ && !fscrypt_disk_encrypted(inode))
return 0;
#endif
if (fsverity_active(inode))
@@ -4090,7 +4108,15 @@ static int __ext4_block_zero_page_range(handle_t
*handle,
if (!buffer_uptodate(bh)) {
err = -EIO;
- ll_rw_block(REQ_OP_READ, 0, 1, &bh);
+ if (S_ISREG(inode->i_mode) && IS_ENCRYPTED(inode)
+ && fscrypt_has_encryption_key(inode)) {
+ bh->b_private = fscrypt_get_diskcipher(inode);
+ ll_rw_block(REQ_OP_READ, bh->b_private ? REQ_CRYPT :
0,
+ 1, &bh);
+ } else {
+ ll_rw_block(REQ_OP_READ, 0, 1, &bh);
+ }
+
wait_on_buffer(bh);
/* Uhhuh. Read error. Complain and punt. */
if (!buffer_uptodate(bh))
@@ -4098,7 +4124,8 @@ static int __ext4_block_zero_page_range(handle_t
*handle,
if (S_ISREG(inode->i_mode) && IS_ENCRYPTED(inode)) {
/* We expect the key to be set. */
BUG_ON(!fscrypt_has_encryption_key(inode));
- WARN_ON_ONCE(fscrypt_decrypt_pagecache_blocks(
+ if (!bh->b_private)
+
WARN_ON_ONCE(fscrypt_decrypt_pagecache_blocks(
page, blocksize, bh_offset(bh)));
}
}
diff --git a/fs/ext4/page-io.c b/fs/ext4/page-io.c
index 12ceadef..3e41788 100644
--- a/fs/ext4/page-io.c
+++ b/fs/ext4/page-io.c
@@ -345,6 +345,11 @@ void ext4_io_submit(struct ext4_io_submit *io)
REQ_SYNC : 0;
io->io_bio->bi_write_hint = io->io_end->inode->i_write_hint;
bio_set_op_attrs(io->io_bio, REQ_OP_WRITE, io_op_flags);
+#if defined(CONFIG_FS_ENCRYPTION) && defined(CONFIG_CRYPTO_DISKCIPHER)
+ if (IS_ENCRYPTED(io->io_end->inode) &&
+ S_ISREG(io->io_end->inode->i_mode))
+ fscrypt_set_bio(io->io_end->inode, io->io_bio, 0);
+#endif
submit_bio(io->io_bio);
}
io->io_bio = NULL;
@@ -474,7 +479,8 @@ int ext4_bio_write_page(struct ext4_io_submit *io,
* (e.g. holes) to be unnecessarily encrypted, but this is rare and
* can't happen in the common case of blocksize == PAGE_SIZE.
*/
- if (IS_ENCRYPTED(inode) && S_ISREG(inode->i_mode) && nr_to_submit) {
+ if (IS_ENCRYPTED(inode) && S_ISREG(inode->i_mode) && nr_to_submit &&
+ !fscrypt_disk_encrypted(inode)) {
gfp_t gfp_flags = GFP_NOFS;
unsigned int enc_bytes = round_up(len, i_blocksize(inode));
diff --git a/fs/ext4/readpage.c b/fs/ext4/readpage.c
index a30b203..aab2cf7c 100644
--- a/fs/ext4/readpage.c
+++ b/fs/ext4/readpage.c
@@ -183,6 +183,9 @@ static struct bio_post_read_ctx
*get_bio_post_read_ctx(struct inode *inode,
unsigned int post_read_steps = 0;
struct bio_post_read_ctx *ctx = NULL;
+ if (fscrypt_disk_encrypted(inode))
+ return NULL;
+
if (IS_ENCRYPTED(inode) && S_ISREG(inode->i_mode))
post_read_steps |= 1 << STEP_DECRYPT;
@@ -376,6 +379,10 @@ int ext4_mpage_readpages(struct address_space *mapping,
bio->bi_private = ctx;
bio_set_op_attrs(bio, REQ_OP_READ,
is_readahead ? REQ_RAHEAD :
0);
+#if defined(CONFIG_FS_ENCRYPTION) && defined(CONFIG_CRYPTO_DISKCIPHER)
+ if (IS_ENCRYPTED(inode) && S_ISREG(inode->i_mode))
+ fscrypt_set_bio(inode, bio, 0);
+#endif
}
length = first_hole << blkbits;
--
2.7.4
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
^ permalink raw reply related
* [PATCH 6/9] dm crypt: support diskcipher
From: boojin.kim @ 2019-08-21 6:42 UTC (permalink / raw)
To: 'Alasdair Kergon', 'Mike Snitzer', dm-devel,
linux-kernel
Cc: 'Ulf Hansson', 'Mike Snitzer', dm-devel,
'Andreas Dilger', 'Alasdair Kergon',
'Eric Biggers', linux-samsung-soc, 'Herbert Xu',
'Krzysztof Kozlowski', 'Jaehoon Chung',
'Kukjin Kim', linux-ext4, 'Chao Yu', linux-block,
linux-fscrypt, 'Jaegeuk Kim', linux-arm-kernel,
'Jens Axboe', 'Theodore Ts'o', linux-mmc,
linux-kernel, linux-f2fs-devel, linux-crypto, linux-fsdevel,
'David S. Miller'
In-Reply-To: <CGME20190821064230epcas2p1ad7301f2b1331bcab3126e6e37c0e272@epcas2p1.samsung.com>
This patch supports dm-crypt to use diskcipher in a specific ivmode
(disk or fmp).
Dm-crypt allocates diskcipher and sets the key on it.
Then, dm-crypt sets diskcipher into BIO and submits the BIO without
any additional data encryption.
Cc: Alasdair Kergon <agk@redhat.com>
Cc: Mike Snitzer <snitzer@redhat.com>
Cc: dm-devel@redhat.com
Signed-off-by: Boojin Kim <boojin.kim@samsung.com>
---
drivers/md/dm-crypt.c | 112
++++++++++++++++++++++++++++++++++++++++++++++----
1 file changed, 103 insertions(+), 9 deletions(-)
diff --git a/drivers/md/dm-crypt.c b/drivers/md/dm-crypt.c
index 9f8b654..271cfcc 100644
--- a/drivers/md/dm-crypt.c
+++ b/drivers/md/dm-crypt.c
@@ -37,6 +37,7 @@
#include <keys/user-type.h>
#include <linux/device-mapper.h>
+#include <crypto/diskcipher.h>
#define DM_MSG_PREFIX "crypt"
@@ -130,6 +131,8 @@ enum flags { DM_CRYPT_SUSPENDED, DM_CRYPT_KEY_VALID,
enum cipher_flags {
CRYPT_MODE_INTEGRITY_AEAD, /* Use authenticated mode for cihper
*/
CRYPT_IV_LARGE_SECTORS, /* Calculate IV from sector_size,
not 512B sectors */
+ CRYPT_MODE_DISKCIPHER,
+ CRYPT_MODE_SKCIPHER,
};
/*
@@ -170,6 +173,7 @@ struct crypt_config {
union {
struct crypto_skcipher **tfms;
struct crypto_aead **tfms_aead;
+ struct crypto_diskcipher **tfms_diskc;
} cipher_tfm;
unsigned tfms_count;
unsigned long cipher_flags;
@@ -955,6 +959,17 @@ static bool crypt_integrity_hmac(struct crypt_config
*cc)
return crypt_integrity_aead(cc) && cc->key_mac_size;
}
+static bool crypt_mode_diskcipher(struct crypt_config *cc)
+{
+ return test_bit(CRYPT_MODE_DISKCIPHER, &cc->cipher_flags);
+}
+
+static bool crypt_mode_skcipher(struct crypt_config *cc)
+{
+ return test_bit(CRYPT_MODE_SKCIPHER, &cc->cipher_flags);
+}
+
+
/* Get sg containing data */
static struct scatterlist *crypt_get_sg_data(struct crypt_config *cc,
struct scatterlist *sg)
@@ -1573,13 +1588,13 @@ static void crypt_endio(struct bio *clone)
/*
* free the processed pages
*/
- if (rw == WRITE)
+ if ((rw == WRITE) && !crypt_mode_diskcipher(cc))
crypt_free_buffer_pages(cc, clone);
error = clone->bi_status;
bio_put(clone);
- if (rw == READ && !error) {
+ if (rw == READ && !error && !crypt_mode_diskcipher(cc)) {
kcryptd_queue_crypt(io);
return;
}
@@ -1618,6 +1633,11 @@ static int kcryptd_io_read(struct dm_crypt_io *io,
gfp_t gfp)
crypt_inc_pending(io);
clone_init(io, clone);
+
+ if (crypt_mode_diskcipher(cc))
+ crypto_diskcipher_set(clone,
+ cc->cipher_tfm.tfms_diskc[0], NULL, 0);
+
clone->bi_iter.bi_sector = cc->start + io->sector;
if (dm_crypt_integrity_io_alloc(io, clone)) {
@@ -1907,10 +1927,29 @@ static void crypt_free_tfms_skcipher(struct
crypt_config *cc)
cc->cipher_tfm.tfms = NULL;
}
+static void crypt_free_tfms_diskcipher(struct crypt_config *cc)
+{
+ if (!crypt_mode_diskcipher(cc))
+ return;
+
+ if (cc->cipher_tfm.tfms_diskc[0] &&
+ !IS_ERR(cc->cipher_tfm.tfms_diskc[0])) {
+ crypto_diskcipher_clearkey(cc->cipher_tfm.tfms_diskc[0]);
+ crypto_free_diskcipher(cc->cipher_tfm.tfms_diskc[0]);
+ cc->cipher_tfm.tfms_diskc[0] = NULL;
+ }
+
+ kfree(cc->cipher_tfm.tfms_diskc);
+ cc->cipher_tfm.tfms_diskc = NULL;
+}
+
+
static void crypt_free_tfms(struct crypt_config *cc)
{
if (crypt_integrity_aead(cc))
crypt_free_tfms_aead(cc);
+ else if (crypt_mode_diskcipher(cc))
+ crypt_free_tfms_diskcipher(cc);
else
crypt_free_tfms_skcipher(cc);
}
@@ -1934,6 +1973,7 @@ static int crypt_alloc_tfms_skcipher(struct
crypt_config *cc, char *ciphermode)
return err;
}
}
+ set_bit(CRYPT_MODE_SKCIPHER, &cc->cipher_flags);
/*
* dm-crypt performance can vary greatly depending on which crypto
@@ -1965,10 +2005,34 @@ static int crypt_alloc_tfms_aead(struct crypt_config
*cc, char *ciphermode)
return 0;
}
+static int crypt_alloc_tfms_diskcipher(struct crypt_config *cc,
+ char *ciphermode)
+{
+ int err;
+
+ cc->cipher_tfm.tfms = kmalloc(sizeof(struct crypto_aead *),
GFP_KERNEL);
+ if (!cc->cipher_tfm.tfms)
+ return -ENOMEM;
+
+ cc->cipher_tfm.tfms_diskc[0] =
+ crypto_alloc_diskcipher(ciphermode, 0, 0, 1);
+ if (IS_ERR(cc->cipher_tfm.tfms_diskc[0])) {
+ err = PTR_ERR(cc->cipher_tfm.tfms_diskc[0]);
+ crypt_free_tfms(cc);
+ pr_err("%s: no diskcipher with %s\n", __func__, ciphermode);
+ return err;
+ }
+ pr_info("%s is done with %s\n", __func__, ciphermode);
+
+ return 0;
+}
+
static int crypt_alloc_tfms(struct crypt_config *cc, char *ciphermode)
{
if (crypt_integrity_aead(cc))
return crypt_alloc_tfms_aead(cc, ciphermode);
+ else if (crypt_mode_diskcipher(cc))
+ return crypt_alloc_tfms_diskcipher(cc, ciphermode);
else
return crypt_alloc_tfms_skcipher(cc, ciphermode);
}
@@ -2030,6 +2094,11 @@ static int crypt_setkey(struct crypt_config *cc)
r = crypto_aead_setkey(cc->cipher_tfm.tfms_aead[i],
cc->key + (i * subkey_size),
subkey_size);
+ else if (crypt_mode_diskcipher(cc))
+ r = crypto_diskcipher_setkey(
+
cc->cipher_tfm.tfms_diskc[i],
+ cc->key + (i * subkey_size),
+ subkey_size, 1);
else
r = crypto_skcipher_setkey(cc->cipher_tfm.tfms[i],
cc->key + (i *
subkey_size),
@@ -2510,7 +2579,7 @@ static int crypt_ctr_cipher_new(struct dm_target *ti,
char *cipher_in, char *key
return -ENOMEM;
}
cc->iv_size = crypto_aead_ivsize(any_tfm_aead(cc));
- } else
+ } else if (crypt_mode_skcipher(cc))
cc->iv_size = crypto_skcipher_ivsize(any_tfm(cc));
ret = crypt_ctr_blkdev_cipher(cc);
@@ -2560,6 +2629,9 @@ static int crypt_ctr_cipher_old(struct dm_target *ti,
char *cipher_in, char *key
chainmode = strsep(&tmp, "-");
*ivmode = strsep(&tmp, ":");
*ivopts = tmp;
+ if (*ivmode)
+ if (!strcmp(*ivmode, "disk") || !strcmp(*ivmode, "fmp"))
+ set_bit(CRYPT_MODE_DISKCIPHER, &cc->cipher_flags);
/*
* For compatibility with the original dm-crypt mapping format, if
@@ -2621,9 +2693,11 @@ static int crypt_ctr_cipher(struct dm_target *ti,
char *cipher_in, char *key)
return ret;
/* Initialize IV */
- ret = crypt_ctr_ivmode(ti, ivmode);
- if (ret < 0)
- return ret;
+ if (!crypt_mode_diskcipher(cc)) {
+ ret = crypt_ctr_ivmode(ti, ivmode);
+ if (ret < 0)
+ return ret;
+ }
/* Initialize and set key */
ret = crypt_set_key(cc, key);
@@ -2654,6 +2728,11 @@ static int crypt_ctr_cipher(struct dm_target *ti,
char *cipher_in, char *key)
if (cc->key_string)
memset(cc->key, 0, cc->key_size * sizeof(u8));
+ pr_info("%s with ivmode:%s, ivopts:%s, aead:%d, diskcipher:%d(%p),
skcipher:%d\n",
+ __func__, ivmode, ivopts, crypt_integrity_aead(cc),
+ crypt_mode_diskcipher(cc),
cc->cipher_tfm.tfms_diskc[0],
+ crypt_mode_skcipher(cc));
+
return ret;
}
@@ -2788,11 +2867,15 @@ static int crypt_ctr(struct dm_target *ti, unsigned
int argc, char **argv)
ret = crypt_ctr_cipher(ti, argv[0], argv[1]);
if (ret < 0)
goto bad;
-
if (crypt_integrity_aead(cc)) {
cc->dmreq_start = sizeof(struct aead_request);
cc->dmreq_start += crypto_aead_reqsize(any_tfm_aead(cc));
align_mask = crypto_aead_alignmask(any_tfm_aead(cc));
+ } else if (crypt_mode_diskcipher(cc)) {
+ cc->per_bio_data_size = ti->per_io_data_size =
+ ALIGN(sizeof(struct dm_crypt_io),
+ ARCH_KMALLOC_MINALIGN);
+ goto get_bio;
} else {
cc->dmreq_start = sizeof(struct skcipher_request);
cc->dmreq_start += crypto_skcipher_reqsize(any_tfm(cc));
@@ -2836,6 +2919,7 @@ static int crypt_ctr(struct dm_target *ti, unsigned
int argc, char **argv)
goto bad;
}
+get_bio:
ret = bioset_init(&cc->bs, MIN_IOS, 0, BIOSET_NEED_BVECS);
if (ret) {
ti->error = "Cannot allocate crypt bioset";
@@ -2893,6 +2977,12 @@ static int crypt_ctr(struct dm_target *ti, unsigned
int argc, char **argv)
goto bad;
}
+ if (crypt_mode_diskcipher(cc)) {
+ cc->crypt_queue = NULL;
+ cc->write_thread = NULL;
+ goto out;
+ }
+
if (test_bit(DM_CRYPT_SAME_CPU, &cc->flags))
cc->crypt_queue = alloc_workqueue("kcryptd/%s",
WQ_HIGHPRI |
WQ_CPU_INTENSIVE | WQ_MEM_RECLAIM,
@@ -2918,6 +3008,7 @@ static int crypt_ctr(struct dm_target *ti, unsigned
int argc, char **argv)
}
wake_up_process(cc->write_thread);
+out:
ti->num_flush_bios = 1;
return 0;
@@ -2981,10 +3072,10 @@ static int crypt_map(struct dm_target *ti, struct
bio *bio)
if (crypt_integrity_aead(cc))
io->ctx.r.req_aead = (struct aead_request *)(io + 1);
- else
+ else if (crypt_mode_skcipher(cc))
io->ctx.r.req = (struct skcipher_request *)(io + 1);
- if (bio_data_dir(io->base_bio) == READ) {
+ if ((bio_data_dir(io->base_bio) == READ) ||
crypt_mode_diskcipher(cc)) {
if (kcryptd_io_read(io, GFP_NOWAIT))
kcryptd_queue_read(io);
} else
@@ -3143,6 +3234,9 @@ static void crypt_io_hints(struct dm_target *ti,
struct queue_limits *limits)
limits->physical_block_size =
max_t(unsigned, limits->physical_block_size,
cc->sector_size);
limits->io_min = max_t(unsigned, limits->io_min, cc->sector_size);
+
+ if (crypt_mode_diskcipher(cc))
+ limits->logical_block_size = PAGE_SIZE;
}
static struct target_type crypt_target = {
--
2.7.4
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
^ permalink raw reply related
* [PATCH 5/9] block: support diskcipher
From: boojin.kim @ 2019-08-21 6:42 UTC (permalink / raw)
To: 'Jens Axboe', linux-block, linux-kernel
Cc: 'Ulf Hansson', 'Mike Snitzer', dm-devel,
'Andreas Dilger', 'Alasdair Kergon',
'Eric Biggers', linux-samsung-soc, 'Herbert Xu',
'Krzysztof Kozlowski', 'Jaehoon Chung',
'Kukjin Kim', linux-ext4, 'Chao Yu', linux-block,
linux-fscrypt, 'Jaegeuk Kim', linux-arm-kernel,
'Jens Axboe', 'Theodore Ts'o', linux-mmc,
linux-kernel, linux-f2fs-devel, linux-crypto, linux-fsdevel,
'David S. Miller'
In-Reply-To: <CGME20190821064226epcas2p2835b8a9084988b79107e54abfc5e7dab@epcas2p2.samsung.com>
This patch supports crypto information to be maintained via BIO
and passed to the storage driver.
To do this, 'bi_aux_private', 'REQ_CYPTE' and 'bi_dun' are added
to the block layer.
'bi_aux_private' is added for loading additional private information into
BIO.
'REQ_CRYPT' is added to distinguish that bi_aux_private is being used
for diskcipher.
F2FS among encryption users uses DUN(device unit number) as
the IV(initial vector) for cryptographic operations.
DUN is stored in 'bi_dun' of bi_iter as a specific value for each BIO.
Before attempting to merge the two BIOs, the operation is also added to
verify that the crypto information contained in two BIOs is consistent.
Cc: Jens Axboe <axboe@kernel.dk>
Signed-off-by: Boojin Kim <boojin.kim@samsung.com>
---
block/bio.c | 1 +
block/blk-merge.c | 19 +++++++++++++++++--
block/bounce.c | 5 ++++-
include/linux/bio.h | 10 ++++++++++
include/linux/blk_types.h | 4 ++++
include/linux/bvec.h | 3 +++
6 files changed, 39 insertions(+), 3 deletions(-)
diff --git a/block/bio.c b/block/bio.c
index 5476965..c60eb8e 100644
--- a/block/bio.c
+++ b/block/bio.c
@@ -588,6 +588,7 @@ void __bio_clone_fast(struct bio *bio, struct bio
*bio_src)
bio->bi_write_hint = bio_src->bi_write_hint;
bio->bi_iter = bio_src->bi_iter;
bio->bi_io_vec = bio_src->bi_io_vec;
+ bio->bi_aux_private = bio_src->bi_aux_private;
bio_clone_blkg_association(bio, bio_src);
blkcg_bio_issue_init(bio);
diff --git a/block/blk-merge.c b/block/blk-merge.c
index 48e6725..d031257 100644
--- a/block/blk-merge.c
+++ b/block/blk-merge.c
@@ -7,6 +7,7 @@
#include <linux/bio.h>
#include <linux/blkdev.h>
#include <linux/scatterlist.h>
+#include <crypto/diskcipher.h>
#include <trace/events/block.h>
@@ -576,6 +577,8 @@ int ll_back_merge_fn(struct request *req, struct bio
*bio, unsigned int nr_segs)
if (blk_integrity_rq(req) &&
integrity_req_gap_back_merge(req, bio))
return 0;
+ if (blk_try_merge(req, bio) != ELEVATOR_BACK_MERGE)
+ return 0;
if (blk_rq_sectors(req) + bio_sectors(bio) >
blk_rq_get_max_sectors(req, blk_rq_pos(req))) {
req_set_nomerge(req->q, req);
@@ -592,6 +595,8 @@ int ll_front_merge_fn(struct request *req, struct bio
*bio, unsigned int nr_segs
if (blk_integrity_rq(req) &&
integrity_req_gap_front_merge(req, bio))
return 0;
+ if (blk_try_merge(req, bio) != ELEVATOR_FRONT_MERGE)
+ return 0;
if (blk_rq_sectors(req) + bio_sectors(bio) >
blk_rq_get_max_sectors(req, bio->bi_iter.bi_sector)) {
req_set_nomerge(req->q, req);
@@ -738,6 +743,9 @@ static struct request *attempt_merge(struct
request_queue *q,
!blk_write_same_mergeable(req->bio, next->bio))
return NULL;
+ if (!crypto_diskcipher_blk_mergeble(req->bio, next->bio))
+ return NULL;
+
/*
* Don't allow merge of different write hints, or for a hint with
* non-hint IO.
@@ -887,9 +895,16 @@ enum elv_merge blk_try_merge(struct request *rq, struct
bio *bio)
{
if (blk_discard_mergable(rq))
return ELEVATOR_DISCARD_MERGE;
- else if (blk_rq_pos(rq) + blk_rq_sectors(rq) ==
bio->bi_iter.bi_sector)
+ else if (blk_rq_pos(rq) + blk_rq_sectors(rq) ==
+ bio->bi_iter.bi_sector) {
+ if (!crypto_diskcipher_blk_mergeble(rq->bio, bio))
+ return ELEVATOR_NO_MERGE;
return ELEVATOR_BACK_MERGE;
- else if (blk_rq_pos(rq) - bio_sectors(bio) ==
bio->bi_iter.bi_sector)
+ } else if (blk_rq_pos(rq) - bio_sectors(bio) ==
+ bio->bi_iter.bi_sector) {
+ if (!crypto_diskcipher_blk_mergeble(bio, rq->bio))
+ return ELEVATOR_NO_MERGE;
return ELEVATOR_FRONT_MERGE;
+ }
return ELEVATOR_NO_MERGE;
}
diff --git a/block/bounce.c b/block/bounce.c
index f8ed677..720b065 100644
--- a/block/bounce.c
+++ b/block/bounce.c
@@ -252,7 +252,10 @@ static struct bio *bounce_clone_bio(struct bio
*bio_src, gfp_t gfp_mask,
bio->bi_write_hint = bio_src->bi_write_hint;
bio->bi_iter.bi_sector = bio_src->bi_iter.bi_sector;
bio->bi_iter.bi_size = bio_src->bi_iter.bi_size;
-
+ bio->bi_aux_private = bio_src->bi_aux_private;
+#ifdef CONFIG_CRYPTO_DISKCIPHER
+ bio->bi_iter.bi_dun = bio_src->bi_iter.bi_dun;
+#endif
switch (bio_op(bio)) {
case REQ_OP_DISCARD:
case REQ_OP_SECURE_ERASE:
diff --git a/include/linux/bio.h b/include/linux/bio.h
index 3cdb84c..351e65e 100644
--- a/include/linux/bio.h
+++ b/include/linux/bio.h
@@ -49,6 +49,12 @@
#define bio_sectors(bio) bvec_iter_sectors((bio)->bi_iter)
#define bio_end_sector(bio) bvec_iter_end_sector((bio)->bi_iter)
+#ifdef CONFIG_CRYPTO_DISKCIPHER
+#define bio_dun(bio) ((bio)->bi_iter.bi_dun)
+#define bio_duns(bio) (bio_sectors(bio) >> 3) /* 4KB unit */
+#define bio_end_dun(bio) (bio_dun(bio) + bio_duns(bio))
+#endif
+
/*
* Return the data direction, READ or WRITE.
*/
@@ -143,6 +149,10 @@ static inline void bio_advance_iter(struct bio *bio,
struct bvec_iter *iter,
{
iter->bi_sector += bytes >> 9;
+#ifdef CONFIG_CRYPTO_DISKCIPHER
+ if (iter->bi_dun)
+ iter->bi_dun += bytes >> 12;
+#endif
if (bio_no_advance_iter(bio))
iter->bi_size -= bytes;
else
diff --git a/include/linux/blk_types.h b/include/linux/blk_types.h
index 75059c1..117119a 100644
--- a/include/linux/blk_types.h
+++ b/include/linux/blk_types.h
@@ -160,6 +160,8 @@ struct bio {
bio_end_io_t *bi_end_io;
void *bi_private;
+ void *bi_aux_private;
+
#ifdef CONFIG_BLK_CGROUP
/*
* Represents the association of the css and request_queue for the
bio.
@@ -311,6 +313,7 @@ enum req_flag_bits {
__REQ_INTEGRITY, /* I/O includes block integrity payload */
__REQ_FUA, /* forced unit access */
__REQ_PREFLUSH, /* request for cache flush */
+ __REQ_CRYPT, /* request inline crypt */
__REQ_RAHEAD, /* read ahead, can fail anytime */
__REQ_BACKGROUND, /* background IO */
__REQ_NOWAIT, /* Don't wait if request will block */
@@ -343,6 +346,7 @@ enum req_flag_bits {
#define REQ_NOMERGE (1ULL << __REQ_NOMERGE)
#define REQ_IDLE (1ULL << __REQ_IDLE)
#define REQ_INTEGRITY (1ULL << __REQ_INTEGRITY)
+#define REQ_CRYPT (1ULL << __REQ_CRYPT)
#define REQ_FUA (1ULL << __REQ_FUA)
#define REQ_PREFLUSH (1ULL << __REQ_PREFLUSH)
#define REQ_RAHEAD (1ULL << __REQ_RAHEAD)
diff --git a/include/linux/bvec.h b/include/linux/bvec.h
index a032f01..5f89641 100644
--- a/include/linux/bvec.h
+++ b/include/linux/bvec.h
@@ -30,6 +30,9 @@ struct bvec_iter {
unsigned int bi_bvec_done; /* number of bytes completed
in
current bvec */
+#ifdef CONFIG_CRYPTO_DISKCIPHER
+ u64 bi_dun;
+#endif
};
struct bvec_iter_all {
--
2.7.4
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
^ permalink raw reply related
* [PATCH 4/9] mmc: dw_mmc-exynos: support FMP
From: boojin.kim @ 2019-08-21 6:42 UTC (permalink / raw)
To: 'Ulf Hansson', 'Kukjin Kim',
'Krzysztof Kozlowski', linux-mmc, linux-arm-kernel,
linux-samsung-soc, linux-kernel
Cc: 'Ulf Hansson', 'Mike Snitzer', dm-devel,
'Andreas Dilger', 'Alasdair Kergon',
'Eric Biggers', linux-samsung-soc, 'Herbert Xu',
'Krzysztof Kozlowski', 'Jaehoon Chung',
'Kukjin Kim', linux-ext4, 'Chao Yu', linux-block,
linux-fscrypt, 'Jaegeuk Kim', linux-arm-kernel,
'Jens Axboe', 'Theodore Ts'o', linux-mmc,
linux-kernel, linux-f2fs-devel, linux-crypto, linux-fsdevel,
'David S. Miller'
In-Reply-To: <CGME20190821064223epcas2p18a14724427711e22c6c76b24bce1c8e0@epcas2p1.samsung.com>
Exynos MMC uses FMP to encrypt data stored on MMC device.
FMP H/W reads crypto information from MMC descriptor.
So, when using FMP H/W, the format of MMC descriptor should be extended.
The FMP driver is registered with the diskcipher algorithm,
so exynos MMC calls diskcipher API to use FMP.
Cc: Ulf Hansson <ulf.hansson@linaro.org>
Cc: Kukjin Kim <kgene@kernel.org>
Cc: Krzysztof Kozlowski <krzk@kernel.org>
Signed-off-by: Boojin Kim <boojin.kim@samsung.com>
---
drivers/mmc/host/Kconfig | 8 ++++++
drivers/mmc/host/dw_mmc-exynos.c | 62
++++++++++++++++++++++++++++++++++++++++
drivers/mmc/host/dw_mmc.c | 26 +++++++++++++++++
3 files changed, 96 insertions(+)
diff --git a/drivers/mmc/host/Kconfig b/drivers/mmc/host/Kconfig
index 14d89a1..f6c5a54 100644
--- a/drivers/mmc/host/Kconfig
+++ b/drivers/mmc/host/Kconfig
@@ -761,6 +761,14 @@ config MMC_DW_EXYNOS
Synopsys DesignWare Memory Card Interface driver. Select this
option
for platforms based on Exynos4 and Exynos5 SoC's.
+config MMC_DW_EXYNOS_FMP
+ tristate "EXYNOS Flash Memory Protector for MMC_DW"
+ depends on MMC_DW_EXYNOS
+ ---help---
+ This selects the EXYNOS MMC_DW FMP Driver.
+
+ If you have a controller with this interface, say Y or M here.
+
config MMC_DW_HI3798CV200
tristate "Hi3798CV200 specific extensions for Synopsys DW Memory
Card Interface"
depends on MMC_DW
diff --git a/drivers/mmc/host/dw_mmc-exynos.c
b/drivers/mmc/host/dw_mmc-exynos.c
index 5e3d95b..d3848ba 100644
--- a/drivers/mmc/host/dw_mmc-exynos.c
+++ b/drivers/mmc/host/dw_mmc-exynos.c
@@ -14,10 +14,12 @@
#include <linux/of_gpio.h>
#include <linux/pm_runtime.h>
#include <linux/slab.h>
+#include <crypto/fmp.h>
#include "dw_mmc.h"
#include "dw_mmc-pltfm.h"
#include "dw_mmc-exynos.h"
+#include "../core/queue.h"
/* Variations in Exynos specific dw-mshc controller */
enum dw_mci_exynos_type {
@@ -508,6 +510,62 @@ static int dw_mci_exynos_prepare_hs400_tuning(struct
dw_mci *host,
return 0;
}
+#ifdef CONFIG_MMC_DW_EXYNOS_FMP
+static struct bio *get_bio(struct dw_mci *host,
+ struct mmc_data *data, bool cmdq_enabled)
+{
+ struct bio *bio = NULL;
+ struct mmc_queue_req *mq_rq = NULL;
+ struct request *req = NULL;
+ struct mmc_blk_request *brq = NULL;
+
+ if (!host || !data) {
+ pr_err("%s: Invalid MMC:%p data:%p\n", __func__, host,
data);
+ return NULL;
+ }
+
+ if (cmdq_enabled) {
+ pr_err("%s: no support cmdq yet:%p\n", __func__, host);
+ bio = NULL;
+ } else {
+ brq = container_of(data, struct mmc_blk_request, data);
+ if (!brq)
+ return NULL;
+
+ mq_rq = container_of(brq, struct mmc_queue_req, brq);
+ if (virt_addr_valid(mq_rq))
+ req = mmc_queue_req_to_req(mq_rq);
+ if (virt_addr_valid(req))
+ bio = req->bio;
+ }
+ return bio;
+}
+
+static int dw_mci_exynos_crypto_engine_cfg(struct dw_mci *host,
+ void *desc, struct mmc_data *data,
+ struct page *page, int page_index,
+ int sector_offset, bool
cmdq_enabled)
+{
+ struct bio *bio = get_bio(host, host->data, cmdq_enabled);
+
+ if (!bio)
+ return 0;
+
+ return exynos_fmp_crypt_cfg(bio, desc, page_index, sector_offset);
+}
+
+static int dw_mci_exynos_crypto_engine_clear(struct dw_mci *host,
+ void *desc, bool cmdq_enabled)
+{
+ struct bio *bio = get_bio(host, host->data, cmdq_enabled);
+
+ if (!bio)
+ return 0;
+
+ return exynos_fmp_crypt_clear(bio, desc);
+}
+#endif
+
/* Common capabilities of Exynos4/Exynos5 SoC */
static unsigned long exynos_dwmmc_caps[4] = {
MMC_CAP_1_8V_DDR | MMC_CAP_8_BIT_DATA | MMC_CAP_CMD23,
@@ -524,6 +582,10 @@ static const struct dw_mci_drv_data exynos_drv_data = {
.parse_dt = dw_mci_exynos_parse_dt,
.execute_tuning = dw_mci_exynos_execute_tuning,
.prepare_hs400_tuning = dw_mci_exynos_prepare_hs400_tuning,
+#ifdef CONFIG_MMC_DW_EXYNOS_FMP
+ .crypto_engine_cfg = dw_mci_exynos_crypto_engine_cfg,
+ .crypto_engine_clear = dw_mci_exynos_crypto_engine_clear,
+#endif
};
static const struct of_device_id dw_mci_exynos_match[] = {
diff --git a/drivers/mmc/host/dw_mmc.c b/drivers/mmc/host/dw_mmc.c
index 0cdf574..4de476a 100644
--- a/drivers/mmc/host/dw_mmc.c
+++ b/drivers/mmc/host/dw_mmc.c
@@ -79,6 +79,32 @@ struct idmac_desc_64addr {
u32 des6; /* Lower 32-bits of Next Descriptor Address
*/
u32 des7; /* Upper 32-bits of Next Descriptor Address
*/
+#if defined(CONFIG_MMC_DW_EXYNOS_FMP)
+ u32 des8; /* File IV 0 */
+ u32 des9; /* File IV 1 */
+ u32 des10; /* File IV 2 */
+ u32 des11; /* File IV 3 */
+ u32 des12; /* File EncKey 0 */
+ u32 des13; /* File EncKey 1 */
+ u32 des14; /* File EncKey 2 */
+ u32 des15; /* File EncKey 3 */
+ u32 des16; /* File EncKey 4 */
+ u32 des17; /* File EncKey 5 */
+ u32 des18; /* File EncKey 6 */
+ u32 des19; /* File EncKey 7 */
+ u32 des20; /* File TwKey 0 */
+ u32 des21; /* File TwKey 1 */
+ u32 des22; /* File TwKey 2 */
+ u32 des23; /* File TwKey 3 */
+ u32 des24; /* File TwKey 4 */
+ u32 des25; /* File TwKey 5 */
+ u32 des26; /* File TwKey 6 */
+ u32 des27; /* File TwKey 7 */
+ u32 des28; /* Disk IV 0 */
+ u32 des29; /* Disk IV 1 */
+ u32 des30; /* Disk IV 2 */
+ u32 des31; /* Disk IV 3 */
+#endif
};
struct idmac_desc {
--
2.7.4
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
^ permalink raw reply related
* [PATCH 2/9] crypto: fmp: add Flash Memory Protector driver
From: boojin.kim @ 2019-08-21 6:42 UTC (permalink / raw)
To: 'Herbert Xu', 'David S. Miller', linux-crypto,
linux-kernel
Cc: 'Ulf Hansson', 'Mike Snitzer', dm-devel,
'Andreas Dilger', 'Alasdair Kergon',
'Eric Biggers', linux-samsung-soc, 'Herbert Xu',
'Krzysztof Kozlowski', 'Jaehoon Chung',
'Kukjin Kim', linux-ext4, 'Chao Yu', linux-block,
linux-fscrypt, 'Jaegeuk Kim', linux-arm-kernel,
'Jens Axboe', 'Theodore Ts'o', linux-mmc,
linux-kernel, linux-f2fs-devel, linux-crypto, linux-fsdevel,
'David S. Miller'
In-Reply-To: <CGME20190821064216epcas2p37df63284df4be04ba2f51b7f7b4b270b@epcas2p3.samsung.com>
Exynos has FMP(Flash Memory Protector) H/W to protect data stored
on storage device.
FMP interworks with the storage controller to encrypt a data before writing
to the storage device and decrypt the data after reading from storage
device.
FMP driver is registered with a cipher algorithm of diskcipher.
FMP driver writes crypto information in the descriptor of the storage
controller.
And then, FMP H/W encrypts plan-text with every write I/O
and decrypts cipher-text with every read I/O.
FMP is divided into three blocks.
The first is fmp driver to control FMP H/W.
The second is the fmp-crypt that is responsible for the interface with
the diskcipher and storage driver.
The third is the fmp-test to test the fmp driver through testmgr of
crypto API.
Cc: Herbert Xu <herbert@gondor.apana.org.au>
Cc: "David S. Miller" <davem@davemloft.net>
Signed-off-by: Boojin Kim <boojin.kim@samsung.com>
---
drivers/crypto/Kconfig | 2 +
drivers/crypto/Makefile | 1 +
drivers/crypto/fmp/Kconfig | 13 +
drivers/crypto/fmp/Makefile | 1 +
drivers/crypto/fmp/fmp.c | 595
+++++++++++++++++++++++++++++++++++++++++
drivers/crypto/fmp/fmp_crypt.c | 243 +++++++++++++++++
drivers/crypto/fmp/fmp_test.c | 310 +++++++++++++++++++++
drivers/crypto/fmp/fmp_test.h | 30 +++
include/crypto/fmp.h | 324 ++++++++++++++++++++++
9 files changed, 1519 insertions(+)
create mode 100644 drivers/crypto/fmp/Kconfig
create mode 100644 drivers/crypto/fmp/Makefile
create mode 100644 drivers/crypto/fmp/fmp.c
create mode 100644 drivers/crypto/fmp/fmp_crypt.c
create mode 100644 drivers/crypto/fmp/fmp_test.c
create mode 100644 drivers/crypto/fmp/fmp_test.h
create mode 100644 include/crypto/fmp.h
diff --git a/drivers/crypto/Kconfig b/drivers/crypto/Kconfig
index b8c5087..43b8cc4 100644
--- a/drivers/crypto/Kconfig
+++ b/drivers/crypto/Kconfig
@@ -785,4 +785,6 @@ config CRYPTO_DEV_CCREE
source "drivers/crypto/hisilicon/Kconfig"
+source "drivers/crypto/fmp/Kconfig"
+
endif # CRYPTO_HW
diff --git a/drivers/crypto/Makefile b/drivers/crypto/Makefile
index afc4753..d43cf7a 100644
--- a/drivers/crypto/Makefile
+++ b/drivers/crypto/Makefile
@@ -48,3 +48,4 @@ obj-$(CONFIG_CRYPTO_DEV_BCM_SPU) += bcm/
obj-$(CONFIG_CRYPTO_DEV_SAFEXCEL) += inside-secure/
obj-$(CONFIG_CRYPTO_DEV_ARTPEC6) += axis/
obj-y += hisilicon/
+obj-$(CONFIG_EXYNOS_FMP) += fmp/
diff --git a/drivers/crypto/fmp/Kconfig b/drivers/crypto/fmp/Kconfig
new file mode 100644
index 0000000..69cdb53
--- /dev/null
+++ b/drivers/crypto/fmp/Kconfig
@@ -0,0 +1,13 @@
+#
+# SMU/FMP controller drivers
+#
+
+config EXYNOS_FMP
+ tristate "Samsung EXYNOS FMP driver"
+ depends on CRYPTO_DISKCIPHER && MMC_DW_EXYNOS_FMP
+ help
+ Say yes here to build support for FMP (Flash Memory Protector)
+ to encrypt and decrypt userdata using inline H/W crypto module.
+ If unsure, say N.
+
+ To compile this driver as a module, choose M here
diff --git a/drivers/crypto/fmp/Makefile b/drivers/crypto/fmp/Makefile
new file mode 100644
index 0000000..5328947
--- /dev/null
+++ b/drivers/crypto/fmp/Makefile
@@ -0,0 +1 @@
+obj-$(CONFIG_EXYNOS_FMP) += fmp_crypt.o fmp.o fmp_test.o
diff --git a/drivers/crypto/fmp/fmp.c b/drivers/crypto/fmp/fmp.c
new file mode 100644
index 0000000..475d471
--- /dev/null
+++ b/drivers/crypto/fmp/fmp.c
@@ -0,0 +1,595 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Exynos FMP driver
+ *
+ * Copyright (C) 2015 Samsung Electronics Co., Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/fs.h>
+#include <linux/slab.h>
+#include <linux/smc.h>
+#include <asm/cacheflush.h>
+#include <linux/crypto.h>
+#include <linux/scatterlist.h>
+#include <crypto/fmp.h>
+
+#include "fmp_test.h"
+
+#define WORD_SIZE 4
+#define FMP_IV_MAX_IDX (FMP_IV_SIZE_16 / WORD_SIZE)
+
+#ifndef __SMC_H__
+#define exynos_smc(a, b, c, d) (-EINVAL)
+#endif
+
+#define byte2word(b0, b1, b2, b3) \
+ (((unsigned int)(b0) << 24) | \
+ ((unsigned int)(b1) << 16) | \
+ ((unsigned int)(b2) << 8) | (b3))
+#define get_word(x, c) byte2word(((unsigned char *)(x) + 4 * (c))[0], \
+ ((unsigned char *)(x) + 4 * (c))[1], \
+ ((unsigned char *)(x) + 4 * (c))[2], \
+ ((unsigned char *)(x) + 4 * (c))[3])
+
+static inline void dump_ci(struct fmp_crypto_info *c)
+{
+ if (c) {
+ pr_info
+ ("%s: crypto:%p algo:%d enc:%d key_size:%d key:%p\n",
+ __func__, c, c->algo_mode, c->enc_mode,
+ c->key_size, c->key);
+ if (c->enc_mode == EXYNOS_FMP_FILE_ENC)
+ print_hex_dump(KERN_CONT, "key:",
+ DUMP_PREFIX_OFFSET, 16, 1, c->key,
+ sizeof(c->key), false);
+ }
+}
+
+static inline void dump_table(struct fmp_table_setting *table)
+{
+ print_hex_dump(KERN_CONT, "dump:", DUMP_PREFIX_OFFSET, 16, 1,
+ table, sizeof(struct fmp_table_setting), false);
+}
+
+static inline int is_set_fmp_disk_key(struct exynos_fmp *fmp)
+{
+ return (fmp->status_disk_key == KEY_SET) ? TRUE : FALSE;
+}
+
+static inline int is_stored_fmp_disk_key(struct exynos_fmp *fmp)
+{
+ return (fmp->status_disk_key == KEY_STORED) ? TRUE : FALSE;
+}
+
+static inline int is_supported_ivsize(u32 ivlen)
+{
+ if (ivlen && (ivlen <= FMP_IV_SIZE_16))
+ return TRUE;
+ else
+ return FALSE;
+}
+
+static inline int check_aes_xts_size(struct fmp_table_setting *table,
+ bool cmdq_enabled)
+{
+ int size;
+
+ if (cmdq_enabled)
+ size = GET_CMDQ_LENGTH(table);
+ else
+ size = GET_LENGTH(table);
+ return (size > MAX_AES_XTS_TRANSFER_SIZE) ? size : 0;
+}
+
+static inline int check_aes_xts_key(char *key,
+ enum fmp_crypto_key_size key_size)
+{
+ char *enckey, *twkey;
+
+ enckey = key;
+ twkey = key + key_size;
+ return (memcmp(enckey, twkey, key_size)) ? 0 : -1;
+}
+
+int fmplib_set_algo_mode(struct fmp_table_setting *table,
+ struct fmp_crypto_info *crypto, bool cmdq_enabled)
+{
+ int ret;
+ enum fmp_crypto_algo_mode algo_mode = crypto->algo_mode;
+
+ if (algo_mode == EXYNOS_FMP_ALGO_MODE_AES_XTS) {
+ ret = check_aes_xts_size(table, cmdq_enabled);
+ if (ret) {
+ pr_err("%s: Fail FMP XTS due to invalid size(%d)\n",
+ __func__, ret);
+ return -EINVAL;
+ }
+ }
+
+ switch (crypto->enc_mode) {
+ case EXYNOS_FMP_FILE_ENC:
+ if (cmdq_enabled)
+ SET_CMDQ_FAS(table, algo_mode);
+ else
+ SET_FAS(table, algo_mode);
+ break;
+ case EXYNOS_FMP_DISK_ENC:
+ if (cmdq_enabled)
+ SET_CMDQ_DAS(table, algo_mode);
+ else
+ SET_DAS(table, algo_mode);
+ break;
+ default:
+ pr_err("%s: Invalid fmp enc mode %d\n", __func__,
+ crypto->enc_mode);
+ return -EINVAL;
+ }
+ return 0;
+}
+
+static int fmplib_set_file_key(struct fmp_table_setting *table,
+ struct fmp_crypto_info *crypto)
+{
+ enum fmp_crypto_algo_mode algo_mode = crypto->algo_mode;
+ enum fmp_crypto_key_size key_size = crypto->fmp_key_size;
+ char *key = crypto->key;
+ int idx, max;
+
+ if (!key || (crypto->enc_mode != EXYNOS_FMP_FILE_ENC) ||
+ ((key_size != EXYNOS_FMP_KEY_SIZE_16) &&
+ (key_size != EXYNOS_FMP_KEY_SIZE_32))) {
+ pr_err("%s: Invalid crypto:%p key:%p key_size:%d
enc_mode:%d\n",
+ __func__, crypto, key, key_size, crypto->enc_mode);
+ return -EINVAL;
+ }
+
+ if ((algo_mode == EXYNOS_FMP_ALGO_MODE_AES_XTS)
+ && check_aes_xts_key(key, key_size)) {
+ pr_err("%s: Fail FMP XTS due to the same enc and twkey\n",
+ __func__);
+ return -EINVAL;
+ }
+
+ if (algo_mode == EXYNOS_FMP_ALGO_MODE_AES_CBC) {
+ max = key_size / WORD_SIZE;
+ for (idx = 0; idx < max; idx++)
+ *(&table->file_enckey0 + idx) =
+ get_word(key, max - (idx + 1));
+ } else if (algo_mode == EXYNOS_FMP_ALGO_MODE_AES_XTS) {
+ key_size *= 2;
+ max = key_size / WORD_SIZE;
+ for (idx = 0; idx < (max / 2); idx++)
+ *(&table->file_enckey0 + idx) =
+ get_word(key, (max / 2) - (idx + 1));
+ for (idx = 0; idx < (max / 2); idx++)
+ *(&table->file_twkey0 + idx) =
+ get_word(key, max - (idx + 1));
+ }
+ return 0;
+}
+
+static int fmplib_set_key_size(struct fmp_table_setting *table,
+ struct fmp_crypto_info *crypto, bool cmdq_enabled)
+{
+ enum fmp_crypto_key_size key_size;
+
+ key_size = crypto->fmp_key_size;
+
+ if ((key_size != EXYNOS_FMP_KEY_SIZE_16) &&
+ (key_size != EXYNOS_FMP_KEY_SIZE_32)) {
+ pr_err("%s: Invalid keysize %d\n", __func__, key_size);
+ return -EINVAL;
+ }
+
+ switch (crypto->enc_mode) {
+ case EXYNOS_FMP_FILE_ENC:
+ if (cmdq_enabled)
+ SET_CMDQ_KEYLEN(table,
+ (key_size ==
+ FMP_KEY_SIZE_32) ? FKL_CMDQ : 0);
+ else
+ SET_KEYLEN(table,
+ (key_size == FMP_KEY_SIZE_32) ? FKL : 0);
+ break;
+ case EXYNOS_FMP_DISK_ENC:
+ if (cmdq_enabled)
+ SET_CMDQ_KEYLEN(table,
+ (key_size ==
+ FMP_KEY_SIZE_32) ? DKL_CMDQ : 0);
+ else
+ SET_KEYLEN(table,
+ (key_size == FMP_KEY_SIZE_32) ? DKL : 0);
+ break;
+ default:
+ pr_err("%s: Invalid fmp enc mode %d\n", __func__,
+ crypto->enc_mode);
+ return -EINVAL;
+ }
+ return 0;
+}
+
+static int fmplib_set_disk_key(struct exynos_fmp *fmp, u8 *key, u32
key_size)
+{
+ int ret;
+
+ /* TODO: only set for host0 */
+ __flush_dcache_area(key, (size_t) FMP_MAX_KEY_SIZE);
+ ret =
+ exynos_smc(SMC_CMD_FMP_DISK_KEY_STORED, 0, virt_to_phys(key),
+ key_size);
+ if (ret) {
+ pr_err("%s: Fail to set FMP disk key. ret = %d\n", __func__,
+ ret);
+ fmp->status_disk_key = KEY_ERROR;
+ return -EINVAL;
+ }
+ fmp->status_disk_key = KEY_STORED;
+ return 0;
+}
+
+static int fmplib_clear_disk_key(struct exynos_fmp *fmp)
+{
+ int ret;
+
+ ret = exynos_smc(SMC_CMD_FMP_DISK_KEY_CLEAR, 0, 0, 0);
+ if (ret) {
+ pr_err("%s: Fail to clear FMP disk key. ret = %d\n",
+ __func__, ret);
+ fmp->status_disk_key = KEY_ERROR;
+ return -EPERM;
+ }
+
+ fmp->status_disk_key = KEY_CLEAR;
+ return 0;
+}
+
+static int fmplib_set_iv(struct fmp_table_setting *table,
+ struct fmp_crypto_info *crypto, u8 *iv)
+{
+ int idx;
+
+ switch (crypto->enc_mode) {
+ case EXYNOS_FMP_FILE_ENC:
+ for (idx = 0; idx < FMP_IV_MAX_IDX; idx++)
+ *(&table->file_iv0 + idx) =
+ get_word(iv, FMP_IV_MAX_IDX - (idx + 1));
+ break;
+ case EXYNOS_FMP_DISK_ENC:
+ for (idx = 0; idx < FMP_IV_MAX_IDX; idx++)
+ *(&table->disk_iv0 + idx) =
+ get_word(iv, FMP_IV_MAX_IDX - (idx + 1));
+ break;
+ default:
+ pr_err("%s: Invalid fmp enc mode %d\n", __func__,
+ crypto->enc_mode);
+ return -EINVAL;
+ }
+ return 0;
+}
+
+int exynos_fmp_crypt(struct fmp_crypto_info *ci, void *priv)
+{
+ struct exynos_fmp *fmp = ci->ctx;
+ struct fmp_request *r = priv;
+ int ret = 0;
+ u8 iv[FMP_IV_SIZE_16];
+
+ if (!r || !fmp) {
+ pr_err("%s: invalid req:%p, fmp:%p\n", __func__, r, fmp);
+ return -EINVAL;
+ }
+
+ /* check test mode */
+ if (ci->algo_mode & EXYNOS_FMP_ALGO_MODE_TEST) {
+ ci->algo_mode &= EXYNOS_FMP_ALGO_MODE_MASK;
+ if (!ci->algo_mode)
+ return 0;
+
+ if (!fmp->test_data) {
+ pr_err("%s: no test_data for test mode\n",
__func__);
+ goto out;
+ }
+ /* use test manager's iv instead of host driver's iv */
+ r->iv = fmp->test_data->iv;
+ r->ivsize = sizeof(fmp->test_data->iv);
+ }
+
+ /* check crypto info & input param */
+ if (!ci->algo_mode || !is_supported_ivsize(r->ivsize) ||
+ !r->table || !r->iv) {
+ dev_err(fmp->dev,
+ "%s: invalid mode:%d iv:%p ivsize:%d table:%p\n",
+ __func__, ci->algo_mode, r->iv, r->ivsize,
r->table);
+ ret = -EINVAL;
+ goto out;
+ }
+
+ /* set algo & enc mode into table */
+ ret = fmplib_set_algo_mode(r->table, ci, r->cmdq_enabled);
+ if (ret) {
+ dev_err(fmp->dev, "%s: Fail to set FMP encryption mode\n",
+ __func__);
+ ret = -EINVAL;
+ goto out;
+ }
+
+ /* set key size into table */
+ switch (ci->enc_mode) {
+ case EXYNOS_FMP_FILE_ENC:
+ ret = fmplib_set_file_key(r->table, ci);
+ if (ret) {
+ dev_err(fmp->dev, "%s: Fail to set FMP key\n",
+ __func__);
+ ret = -EINVAL;
+ goto out;
+ }
+ break;
+ case EXYNOS_FMP_DISK_ENC:
+ if (is_stored_fmp_disk_key(fmp)) {
+ ret = exynos_smc(SMC_CMD_FMP_DISK_KEY_SET, 0, 0, 0);
+ if (ret) {
+ dev_err(fmp->dev,
+ "%s: Fail to set disk key\n",
__func__);
+ goto out;
+ }
+ fmp->status_disk_key = KEY_SET;
+ } else if (!is_set_fmp_disk_key(fmp)) {
+ dev_err(fmp->dev,
+ "%s: Fail because disk key is clear\n",
+ __func__);
+ ret = -EINVAL;
+ goto out;
+ }
+ break;
+ default:
+ dev_err(fmp->dev, "%s: Invalid fmp enc mode %d\n", __func__,
+ ci->enc_mode);
+ ret = -EINVAL;
+ goto out;
+ }
+
+ /* set key size into table */
+ ret = fmplib_set_key_size(r->table, ci, r->cmdq_enabled);
+ if (ret) {
+ dev_err(fmp->dev, "%s: Fail to set FMP key size\n",
__func__);
+ ret = -EINVAL;
+ goto out;
+ }
+
+ /* set iv */
+ memset(iv, 0, FMP_IV_SIZE_16);
+ memcpy(iv, r->iv, r->ivsize);
+ ret = fmplib_set_iv(r->table, ci, iv);
+ if (ret) {
+ dev_err(fmp->dev, "%s: Fail to set FMP IV\n", __func__);
+ ret = -EINVAL;
+ goto out;
+ }
+out:
+ if (ret) {
+ dump_ci(ci);
+ if (r && r->table)
+ dump_table(r->table);
+ }
+ return ret;
+}
+
+static inline void fmplib_clear_file_key(struct fmp_table_setting *table)
+{
+ memset(&table->file_iv0, 0, sizeof(__le32) * 24);
+}
+
+int exynos_fmp_clear(struct fmp_crypto_info *ci, void *priv)
+{
+ struct fmp_request *r = priv;
+
+ if (!r) {
+ pr_err("%s: Invalid input\n", __func__);
+ return -EINVAL;
+ }
+
+ if (!r->table) {
+ pr_err("%s: Invalid input table\n", __func__);
+ return -EINVAL;
+ }
+
+ fmplib_clear_file_key(r->table);
+ return 0;
+}
+
+int exynos_fmp_setkey(struct fmp_crypto_info *ci, u8 *in_key, u32 keylen,
+ bool persistent)
+{
+ struct exynos_fmp *fmp = ci->ctx;
+ int ret = 0;
+ int keylen_org = keylen;
+
+ if (!fmp || !in_key) {
+ pr_err("%s: invalid input param\n", __func__);
+ return -EINVAL;
+ }
+
+ /* set key_size & fmp_key_size */
+ if (ci->algo_mode == EXYNOS_FMP_ALGO_MODE_AES_XTS)
+ keylen = keylen >> 1;
+ switch (keylen) {
+ case FMP_KEY_SIZE_16:
+ ci->fmp_key_size = EXYNOS_FMP_KEY_SIZE_16;
+ break;
+ case FMP_KEY_SIZE_32:
+ ci->fmp_key_size = EXYNOS_FMP_KEY_SIZE_32;
+ break;
+ default:
+ pr_err("%s: FMP doesn't support key size %d\n", __func__,
+ keylen);
+ return -ENOKEY;
+ }
+ ci->key_size = keylen_org;
+
+ /* set key */
+ if (persistent) {
+ ci->enc_mode = EXYNOS_FMP_DISK_ENC;
+ ret = fmplib_set_disk_key(fmp, in_key, ci->key_size);
+ if (ret)
+ pr_err("%s: Fail to set FMP disk key\n", __func__);
+ } else {
+ ci->enc_mode = EXYNOS_FMP_FILE_ENC;
+ memset(ci->key, 0, sizeof(ci->key));
+ memcpy(ci->key, in_key, ci->key_size);
+ }
+ return ret;
+}
+
+int exynos_fmp_clearkey(struct fmp_crypto_info *ci)
+{
+ struct exynos_fmp *fmp = ci->ctx;
+ int ret = 0;
+
+ if (!fmp) {
+ pr_err("%s: invalid input param\n", __func__);
+ ret = -EINVAL;
+ goto out;
+ }
+
+ if (ci->enc_mode == EXYNOS_FMP_DISK_ENC) {
+ ret = fmplib_clear_disk_key(fmp);
+ if (ret)
+ pr_err("%s: fail to clear FMP disk key\n",
__func__);
+ } else if (ci->enc_mode == EXYNOS_FMP_FILE_ENC) {
+ memset(ci->key, 0, sizeof(ci->key));
+ ci->key_size = 0;
+ } else {
+ pr_err("%s: invalid algo mode:%d\n", __func__,
ci->enc_mode);
+ ret = -EINVAL;
+ }
+out:
+ return ret;
+}
+
+int exynos_fmp_test_crypt(struct fmp_crypto_info *ci,
+ const uint8_t *iv, uint32_t ivlen, uint8_t *src,
+ uint8_t *dst, uint32_t len, bool enc, void *priv)
+{
+ struct exynos_fmp *fmp = ci->ctx;
+ int ret = 0;
+
+ if (!fmp || !iv || !src || !dst) {
+ pr_err("%s: invalid input: fmp:%p, iv:%p, s:%p, d:%p\n",
+ __func__, fmp, iv, src, dst);
+ return -EINVAL;
+ }
+
+ /* init fmp test to get test block */
+ fmp->test_data = fmp_test_init(fmp);
+ if (!fmp->test_data) {
+ dev_err(fmp->dev, "%s: fail to initialize fmp test.",
+ __func__);
+ goto err;
+ }
+
+ /* setiv */
+ if (iv && (ivlen <= FMP_IV_SIZE_16)) {
+ memset(fmp->test_data->iv, 0, FMP_IV_SIZE_16);
+ memcpy(fmp->test_data->iv, iv, ivlen);
+ } else {
+ dev_err(fmp->dev, "%s: fail to set fmp iv. ret(%d)",
+ __func__, ret);
+ goto err;
+ }
+
+ /* do crypt: priv: struct crypto_diskcipher */
+ ret = fmp_test_crypt(fmp, fmp->test_data,
+ src, dst, len, enc ? ENCRYPT : DECRYPT, priv, ci);
+ if (ret)
+ dev_err(fmp->dev, "%s: fail to run fmp test. ret(%d)",
+ __func__, ret);
+
+err:
+ if (fmp->test_data)
+ fmp_test_exit(fmp->test_data);
+ return ret;
+}
+
+int exynos_fmp_smu_abort(int id)
+{
+ int ret = 0;
+
+ if (id == SMU_ID_MAX)
+ return 0;
+
+ ret = exynos_smc(SMC_CMD_SMU, SMU_ABORT, id, 0);
+ if (ret)
+ pr_err("%s: Fail smc call. ret(%d)\n", __func__, ret);
+
+ return ret;
+}
+
+#define CFG_DESCTYPE_3 0x3
+int exynos_fmp_sec_cfg(int fmp_id, int smu_id, bool init)
+{
+ int ret = 0;
+
+ if (fmp_id != SMU_ID_MAX) {
+ ret = exynos_smc(SMC_CMD_FMP_SECURITY, 0,
+ fmp_id, CFG_DESCTYPE_3);
+ if (ret)
+ pr_err("%s: Fail smc call for FMP_SECURITY.
ret(%d)\n",
+ __func__, ret);
+ }
+
+ if (smu_id != SMU_ID_MAX) {
+ if (init)
+ ret = exynos_smc(SMC_CMD_SMU, SMU_INIT, smu_id, 0);
+ else
+ ret = exynos_smc(SMC_CMD_FMP_SMU_RESUME, 0, smu_id,
0);
+ if (ret)
+ pr_err("%s: Fail smc call cmd:%d. ret(%d)\n",
+ __func__, init, ret);
+ }
+
+ return ret;
+}
+
+void *exynos_fmp_init(struct platform_device *pdev)
+{
+ struct exynos_fmp *fmp;
+
+ if (!pdev) {
+ pr_err("%s: Invalid platform_device.\n", __func__);
+ return NULL;
+ }
+
+ fmp = devm_kzalloc(&pdev->dev, sizeof(struct exynos_fmp),
GFP_KERNEL);
+ if (!fmp)
+ return NULL;
+
+ fmp->dev = &pdev->dev;
+ if (!fmp->dev) {
+ pr_err("%s: Invalid device.\n", __func__);
+ goto err_dev;
+ }
+
+ /* init disk key status */
+ fmp->status_disk_key = KEY_CLEAR;
+
+ dev_info(fmp->dev, "Exynos FMP Version: %s\n", FMP_DRV_VERSION);
+ return fmp;
+
+err_dev:
+ kzfree(fmp);
+ return NULL;
+}
+
+void exynos_fmp_exit(struct exynos_fmp *fmp)
+{
+ kzfree(fmp);
+}
diff --git a/drivers/crypto/fmp/fmp_crypt.c b/drivers/crypto/fmp/fmp_crypt.c
new file mode 100644
index 0000000..78becb5
--- /dev/null
+++ b/drivers/crypto/fmp/fmp_crypt.c
@@ -0,0 +1,243 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Exynos FMP crypt interface
+ *
+ * Copyright (C) 2018 Samsung Electronics Co., Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/slab.h>
+#include <linux/bio.h>
+#include <linux/crypto.h>
+#include <linux/scatterlist.h>
+#include <crypto/fmp.h>
+#include <crypto/diskcipher.h>
+
+int exynos_fmp_crypt_clear(struct bio *bio, void *table_addr)
+{
+ struct crypto_diskcipher *dtfm = crypto_diskcipher_get(bio);
+ struct fmp_crypto_info *ci;
+ struct fmp_request req;
+ int ret = 0;
+
+ if (unlikely(IS_ERR(dtfm))) {
+ pr_warn("%s: fails to get crypt\n", __func__);
+ return -EINVAL;
+ } else if (dtfm) {
+ ci = crypto_tfm_ctx(crypto_diskcipher_tfm(dtfm));
+ if (ci)
+ if (ci->enc_mode == EXYNOS_FMP_FILE_ENC) {
+ req.table = table_addr;
+ ret = crypto_diskcipher_clear_crypt(dtfm,
&req);
+ }
+ }
+ if (ret)
+ pr_err("%s: fail to config desc (bio:%p, tfm:%p, ci:%p
ret:%d)\n",
+ __func__, bio, dtfm, ci, ret);
+ return ret;
+}
+
+int exynos_fmp_crypt_cfg(struct bio *bio, void *table_addr,
+ u32 page_idx, u32 sector_unit)
+{
+ struct crypto_diskcipher *dtfm = crypto_diskcipher_get(bio);
+ u64 iv;
+ struct fmp_request req;
+ int ret = 0;
+
+ if (unlikely(IS_ERR(dtfm))) {
+ pr_warn("%s: fails to get crypt\n", __func__);
+ return -EINVAL;
+ } else if (dtfm) {
+ req.table = table_addr;
+ req.cmdq_enabled = 0;
+ req.iv = &iv;
+ req.ivsize = sizeof(iv);
+ iv = (dtfm->ivmode == IV_MODE_DUN) ? (bio_dun(bio) +
page_idx) :
+ (bio->bi_iter.bi_sector + (sector_t)sector_unit);
+ ret = crypto_diskcipher_set_crypt(dtfm, &req);
+ if (ret)
+ pr_err("%s: fail to config desc (bio:%p, tfm:%p,
ret:%d)\n",
+ __func__, bio, dtfm, ret);
+ return ret;
+ }
+
+ exynos_fmp_bypass(table_addr, 0);
+ return 0;
+}
+
+static int fmp_crypt(struct crypto_diskcipher *tfm, void *priv)
+{
+ struct fmp_crypto_info *ci =
crypto_tfm_ctx(crypto_diskcipher_tfm(tfm));
+
+ return exynos_fmp_crypt(ci, priv);
+}
+
+static int fmp_clear(struct crypto_diskcipher *tfm, void *priv)
+{
+ struct fmp_crypto_info *ci =
crypto_tfm_ctx(crypto_diskcipher_tfm(tfm));
+
+ return exynos_fmp_clear(ci, priv);
+}
+
+static int fmp_setkey(struct crypto_diskcipher *tfm, const char *in_key,
+ u32 keylen, bool persistent)
+{
+ struct fmp_crypto_info *ci =
crypto_tfm_ctx(crypto_diskcipher_tfm(tfm));
+
+ return exynos_fmp_setkey(ci, (char *)in_key, keylen, persistent);
+}
+
+static int fmp_clearkey(struct crypto_diskcipher *tfm)
+{
+ struct fmp_crypto_info *ci =
crypto_tfm_ctx(crypto_diskcipher_tfm(tfm));
+
+ return exynos_fmp_clearkey(ci);
+}
+
+/* support crypto manager test without CRYPTO_MANAGER_DISABLE_TESTS */
+static int fmp_do_test_crypt(struct crypto_diskcipher *tfm,
+ struct diskcipher_test_request *req)
+{
+ if (!req) {
+ pr_err("%s: invalid parameter\n", __func__);
+ return -EINVAL;
+ }
+
+ return
exynos_fmp_test_crypt(crypto_tfm_ctx(crypto_diskcipher_tfm(tfm)),
+ req->iv, tfm->ivsize,
+ sg_virt(req->src), sg_virt(req->dst),
+ req->cryptlen, req->enc ? 1 : 0, tfm);
+}
+
+
+static inline void fmp_algo_init(struct crypto_tfm *tfm,
+ enum fmp_crypto_algo_mode algo)
+{
+ struct fmp_crypto_info *ci = crypto_tfm_ctx(tfm);
+ struct crypto_diskcipher *diskc = __crypto_diskcipher_cast(tfm);
+ struct diskcipher_alg *alg = crypto_diskcipher_alg(diskc);
+
+ /* This field's stongly aligned 'fmp_crypto_info->use_diskc' */
+ diskc->algo = (u32)algo;
+ diskc->ivsize = FMP_IV_SIZE_16;
+ ci->ctx = dev_get_drvdata(alg->dev);
+ ci->algo_mode = algo;
+}
+
+static int fmp_aes_xts_init(struct crypto_tfm *tfm)
+{
+ fmp_algo_init(tfm, EXYNOS_FMP_ALGO_MODE_AES_XTS);
+ return 0;
+}
+
+static int fmp_cbc_aes_init(struct crypto_tfm *tfm)
+{
+ fmp_algo_init(tfm, EXYNOS_FMP_ALGO_MODE_AES_CBC);
+ return 0;
+}
+
+static struct diskcipher_alg fmp_algs[] = {{
+ .base = {
+ .cra_name = "xts(aes)-disk",
+ .cra_driver_name = "xts(aes)-disk(fmp)",
+ .cra_priority = 200,
+ .cra_module = THIS_MODULE,
+ .cra_ctxsize = sizeof(struct fmp_crypto_info),
+ .cra_init = fmp_aes_xts_init,
+ }
+}, {
+ .base = {
+ .cra_name = "cbc(aes)-disk",
+ .cra_driver_name = "cbc(aes)-disk(fmp)",
+ .cra_priority = 200,
+ .cra_module = THIS_MODULE,
+ .cra_ctxsize = sizeof(struct fmp_crypto_info),
+ .cra_init = fmp_cbc_aes_init,
+ }
+} };
+
+static int exynos_fmp_probe(struct platform_device *pdev)
+{
+ struct diskcipher_alg *alg;
+ void *fmp_ctx = exynos_fmp_init(pdev);
+ int ret;
+ int i;
+
+ if (!fmp_ctx) {
+ dev_err(&pdev->dev,
+ "%s: Fail to register diskciphero\n", __func__);
+ return -EINVAL;
+ }
+ dev_set_drvdata(&pdev->dev, fmp_ctx);
+
+ for (i = 0; i < ARRAY_SIZE(fmp_algs); i++) {
+ alg = &fmp_algs[i];
+ alg->dev = &pdev->dev;
+ alg->init = NULL;
+ alg->setkey = fmp_setkey;
+ alg->clearkey = fmp_clearkey;
+ alg->crypt = fmp_crypt;
+ alg->clear = fmp_clear;
+ alg->do_crypt = fmp_do_test_crypt;
+ }
+ ret = crypto_register_diskciphers(fmp_algs, ARRAY_SIZE(fmp_algs));
+ if (ret) {
+ dev_err(&pdev->dev,
+ "%s: Fail to register diskciphero. ret = %d\n",
+ __func__, ret);
+ return -EINVAL;
+ }
+ dev_info(&pdev->dev, "Exynos FMP driver is registered to
diskcipher\n");
+ return 0;
+}
+
+static int exynos_fmp_remove(struct platform_device *pdev)
+{
+ void *drv_data = dev_get_drvdata(&pdev->dev);
+
+ if (!drv_data) {
+ pr_err("%s: Fail to get drvdata\n", __func__);
+ return 0;
+ }
+ crypto_unregister_diskciphers(fmp_algs, ARRAY_SIZE(fmp_algs));
+ exynos_fmp_exit(drv_data);
+ return 0;
+}
+
+static const struct of_device_id exynos_fmp_match[] = {
+ { .compatible = "samsung,exynos-fmp" },
+ {},
+};
+
+static struct platform_driver exynos_fmp_driver = {
+ .driver = {
+ .name = "exynos-fmp",
+ .owner = THIS_MODULE,
+ .pm = NULL,
+ .of_match_table = exynos_fmp_match,
+ },
+ .probe = exynos_fmp_probe,
+ .remove = exynos_fmp_remove,
+};
+
+static int __init fmp_init(void)
+{
+ return platform_driver_register(&exynos_fmp_driver);
+}
+late_initcall(fmp_init);
+
+static void __exit fmp_exit(void)
+{
+ platform_driver_unregister(&exynos_fmp_driver);
+}
+module_exit(fmp_exit);
+MODULE_DESCRIPTION("Exynos Spedific crypto algo driver");
diff --git a/drivers/crypto/fmp/fmp_test.c b/drivers/crypto/fmp/fmp_test.c
new file mode 100644
index 0000000..fb47bbd
--- /dev/null
+++ b/drivers/crypto/fmp/fmp_test.c
@@ -0,0 +1,310 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Exynos FMP cipher driver
+ *
+ * Copyright (C) 2016 Samsung Electronics Co., Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#include <linux/of.h>
+#include <linux/of_platform.h>
+#include <linux/crypto.h>
+#include <linux/buffer_head.h>
+#include <linux/genhd.h>
+#include <linux/delay.h>
+#include <linux/fs.h>
+#include <linux/blk_types.h>
+#include <crypto/fmp.h>
+
+#include "fmp_test.h"
+
+#define MAX_SCAN_PART (50)
+#define MAX_RETRY_COUNT (0x100000)
+
+static dev_t find_devt_for_test(struct exynos_fmp *fmp,
+ struct fmp_test_data *data)
+{
+ int i, idx = 0;
+ uint32_t count = 0;
+ uint64_t size;
+ uint64_t size_list[MAX_SCAN_PART];
+ dev_t devt_list[MAX_SCAN_PART];
+ dev_t devt_scan = 0;
+ dev_t devt = 0;
+ struct block_device *bdev = NULL;
+ struct device *dev = fmp->dev;
+ fmode_t fmode = FMODE_WRITE | FMODE_READ;
+
+ memset(size_list, 0, sizeof(size_list));
+ memset(devt_list, 0, sizeof(devt_list));
+ do {
+ for (i = 1; i < MAX_SCAN_PART; i++) {
+ devt_scan = blk_lookup_devt(data->block_type, i);
+ bdev = blkdev_get_by_dev(devt_scan, fmode, NULL);
+ if (IS_ERR(bdev))
+ continue;
+ else {
+ size_list[idx] =
+ (uint64_t) i_size_read(bdev->bd_inode);
+ devt_list[idx++] = devt_scan;
+ blkdev_put(bdev, fmode);
+ }
+ }
+ if (!idx) {
+ mdelay(100);
+ count++;
+ continue;
+ }
+ for (i = 0; i < idx; i++) {
+ if (i == 0) {
+ size = size_list[i];
+ devt = devt_list[i];
+ } else {
+ if (size < size_list[i])
+ devt = devt_list[i];
+ }
+ }
+ bdev = blkdev_get_by_dev(devt, fmode, NULL);
+ dev_dbg(dev, "Found partno %d for FMP test\n",
+ bdev->bd_part->partno);
+ blkdev_put(bdev, fmode);
+ return devt;
+ } while (count < MAX_RETRY_COUNT);
+ dev_err(dev, "Block device isn't initialized yet for FMP test\n");
+ return (dev_t) 0;
+}
+
+static int get_fmp_host_type(struct device *dev,
+ struct fmp_test_data *data)
+{
+ int ret;
+ struct device_node *node = dev->of_node;
+ const char *type;
+
+ ret =
+ of_property_read_string_index(node, "exynos,block-type", 0,
&type);
+ if (ret) {
+ pr_err("%s: Could not get block type\n", __func__);
+ return ret;
+ }
+ strscpy(data->block_type, type, FMP_BLOCK_TYPE_NAME_LEN);
+ return 0;
+}
+
+static int get_fmp_test_block_offset(struct device *dev,
+ struct fmp_test_data *data)
+{
+ int ret = 0;
+ struct device_node *node = dev->of_node;
+ uint32_t offset;
+
+ ret = of_property_read_u32(node, "exynos,fips-block_offset",
&offset);
+ if (ret) {
+ pr_err("%s: Could not get fips test block offset\n",
__func__);
+ ret = -EINVAL;
+ goto err;
+ }
+ data->test_block_offset = offset;
+err:
+ return ret;
+}
+
+/* test block device init for fmp test */
+struct fmp_test_data *fmp_test_init(struct exynos_fmp *fmp)
+{
+ int ret = 0;
+ struct fmp_test_data *data;
+ struct device *dev;
+ struct inode *inode;
+ struct super_block *sb;
+ unsigned long blocksize;
+ unsigned char blocksize_bits;
+ fmode_t fmode = FMODE_WRITE | FMODE_READ;
+
+ if (!fmp) {
+ pr_err("%s: Invalid exynos fmp struct\n", __func__);
+ return NULL;
+ }
+
+ dev = fmp->dev;
+ data = kmalloc(sizeof(struct fmp_test_data), GFP_KERNEL);
+ if (!data)
+ return NULL;
+
+ ret = get_fmp_host_type(dev, data);
+ if (ret) {
+ dev_err(dev, "%s: Fail to get host type. ret(%d)", __func__,
+ ret);
+ goto err;
+ }
+ data->devt = find_devt_for_test(fmp, data);
+ if (!data->devt) {
+ dev_err(dev, "%s: Fail to find devt for self test\n",
__func__);
+ goto err;
+ }
+ data->bdev = blkdev_get_by_dev(data->devt, fmode, NULL);
+ if (IS_ERR(data->bdev)) {
+ dev_err(dev, "%s: Fail to open block device\n", __func__);
+ goto err;
+ }
+ ret = get_fmp_test_block_offset(dev, data);
+ if (ret) {
+ dev_err(dev, "%s: Fail to get fips offset. ret(%d)\n",
+ __func__, ret);
+ goto err;
+ }
+ inode = data->bdev->bd_inode;
+ sb = inode->i_sb;
+ blocksize = sb->s_blocksize;
+ blocksize_bits = sb->s_blocksize_bits;
+ data->sector =
+ (i_size_read(inode) -
+ (blocksize * data->test_block_offset)) >> blocksize_bits;
+
+ return data;
+err:
+ kzfree(data);
+ return NULL;
+}
+
+int fmp_cipher_run(struct exynos_fmp *fmp, struct fmp_test_data *fdata,
+ uint8_t *data, uint32_t len, bool bypass, uint32_t write,
+ void *priv, struct fmp_crypto_info *ci)
+{
+ int ret = 0;
+ struct device *dev;
+ static struct buffer_head *bh;
+ u32 org_algo_mode;
+ int op_flags;
+
+ if (!fmp || !fdata || !ci) {
+ pr_err("%s: Invalid fmp struct: %p, %p, %p\n",
+ __func__, fmp, fdata, ci);
+ return -EINVAL;
+ }
+ dev = fmp->dev;
+
+ bh = __getblk(fdata->bdev, fdata->sector, FMP_BLK_SIZE);
+ if (!bh) {
+ dev_err(dev, "%s: Fail to get block from bdev\n", __func__);
+ return -ENODEV;
+ }
+
+ /* set algo_mode for test */
+ org_algo_mode = ci->algo_mode;
+ if (bypass)
+ ci->algo_mode = EXYNOS_FMP_BYPASS_MODE;
+ ci->algo_mode |= EXYNOS_FMP_ALGO_MODE_TEST;
+
+ get_bh(bh);
+ /* priv is diskc for crypto test. */
+ if (!priv) {
+ /* ci is fmp_test_data->ci */
+ fmp->test_data = fdata;
+ ci->ctx = fmp;
+ ci->use_diskc = 0;
+ ci->enc_mode = EXYNOS_FMP_FILE_ENC;
+ bh->b_private = ci;
+ } else {
+ /* ci is crypto_tfm_ctx(tfm) */
+ bh->b_private = priv;
+ }
+ op_flags = REQ_CRYPT;
+
+ if (write == WRITE_MODE) {
+ memcpy(bh->b_data, data, len);
+ set_buffer_dirty(bh);
+ ret = __sync_dirty_buffer(bh, op_flags | REQ_SYNC);
+ if (ret) {
+ dev_err(dev, "%s: IO error syncing for write
mode\n",
+ __func__);
+ ret = -EIO;
+ goto out;
+ }
+ memset(bh->b_data, 0, FMP_BLK_SIZE);
+ } else {
+ lock_buffer(bh);
+ bh->b_end_io = end_buffer_read_sync;
+ submit_bh(REQ_OP_READ, REQ_SYNC | REQ_PRIO | op_flags, bh);
+ wait_on_buffer(bh);
+ if (unlikely(!buffer_uptodate(bh))) {
+ ret = -EIO;
+ goto out;
+ }
+ memcpy(data, bh->b_data, len);
+ }
+out:
+ if (ci)
+ ci->algo_mode = org_algo_mode;
+ put_bh(bh);
+ return ret;
+}
+
+int fmp_test_crypt(struct exynos_fmp *fmp, struct fmp_test_data *fdata,
+ uint8_t *src, uint8_t *dst, uint32_t len, uint32_t enc,
+ void *priv, struct fmp_crypto_info *ci)
+{
+ int ret = 0;
+
+ if (!fdata) {
+ pr_err("%s: Invalid exynos fmp struct\n", __func__);
+ return -1;
+ }
+
+ if (enc == ENCRYPT) {
+ ret = fmp_cipher_run(fmp, fdata, src, len, 0,
+ WRITE_MODE, priv, ci);
+ if (ret) {
+ pr_err("Fail to run fmp cipher ret(%d)\n",
+ ret);
+ goto err;
+ }
+ ret = fmp_cipher_run(fmp, fdata, dst, len, 1,
+ READ_MODE, priv, ci);
+ if (ret) {
+ pr_err("Fail to run fmp cipher ret(%d)\n",
+ ret);
+ goto err;
+ }
+ } else if (enc == DECRYPT) {
+ ret = fmp_cipher_run(fmp, fdata, src, len, 1,
+ WRITE_MODE, priv, ci);
+ if (ret) {
+ pr_err("Fail to run fmp cipher ret(%d)\n",
+ ret);
+ goto err;
+ }
+ ret = fmp_cipher_run(fmp, fdata, dst, len, 0,
+ READ_MODE, priv, ci);
+ if (ret) {
+ pr_err("Fail to run fmp cipher ret(%d)\n",
+ ret);
+ goto err;
+ }
+ } else {
+ pr_err("%s: Invalid enc %d mode\n", __func__, enc);
+ goto err;
+ }
+
+ return 0;
+err:
+ return -EINVAL;
+}
+
+/* test block device release for fmp test */
+void fmp_test_exit(struct fmp_test_data *fdata)
+{
+ fmode_t fmode = FMODE_WRITE | FMODE_READ;
+
+ if (!fdata) {
+ pr_err("%s: Invalid exynos fmp struct\n", __func__);
+ return;
+ }
+ if (fdata->bdev)
+ blkdev_put(fdata->bdev, fmode);
+ kzfree(fdata);
+}
diff --git a/drivers/crypto/fmp/fmp_test.h b/drivers/crypto/fmp/fmp_test.h
new file mode 100644
index 0000000..42af22a
--- /dev/null
+++ b/drivers/crypto/fmp/fmp_test.h
@@ -0,0 +1,30 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+/*
+ * Copyright (C) 2016 Samsung Electronics Co., Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#ifndef _FMP_TEST_H_
+#define _FMP_TEST_H_
+
+#define FMP_BLK_SIZE (4096)
+
+#define WRITE_MODE 1
+#define READ_MODE 2
+
+#define ENCRYPT 1
+#define DECRYPT 2
+
+struct fmp_test_data *fmp_test_init(struct exynos_fmp *fmp);
+int fmp_cipher_run(struct exynos_fmp *fmp, struct fmp_test_data *fdata,
+ uint8_t *data, uint32_t len, bool bypass, uint32_t write,
+ void *priv, struct fmp_crypto_info *ci);
+int fmp_test_crypt(struct exynos_fmp *fmp, struct fmp_test_data *fdata,
+ uint8_t *src, uint8_t *dst, uint32_t len, uint32_t enc,
+ void *priv, struct fmp_crypto_info *ci);
+void fmp_test_exit(struct fmp_test_data *fdata);
+#endif /* _FMP_TEST_H_ */
diff --git a/include/crypto/fmp.h b/include/crypto/fmp.h
new file mode 100644
index 0000000..b0ac483
--- /dev/null
+++ b/include/crypto/fmp.h
@@ -0,0 +1,324 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+/*
+ * Copyright (C) 2016 Samsung Electronics Co., Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#ifndef _EXYNOS_FMP_H_
+#define _EXYNOS_FMP_H_
+
+#include <linux/platform_device.h>
+#include <linux/miscdevice.h>
+
+#define FMP_DRV_VERSION "1.5.0"
+
+#define FMP_KEY_SIZE_16 16
+#define FMP_KEY_SIZE_32 32
+#define FMP_IV_SIZE_16 16
+
+#define FMP_CBC_MAX_KEY_SIZE FMP_KEY_SIZE_16
+#define FMP_XTS_MAX_KEY_SIZE ((FMP_KEY_SIZE_32) * (2))
+#define FMP_MAX_KEY_SIZE FMP_XTS_MAX_KEY_SIZE
+
+#define FMP_HOST_TYPE_NAME_LEN 8
+#define FMP_BLOCK_TYPE_NAME_LEN 8
+
+#define FMP_SECTOR_SIZE 0x1000
+#define FMP_MIN_SECTOR_SIZE 0x200
+#define NUM_SECTOR_UNIT ((FMP_SECTOR_SIZE)/(FMP_MIN_SECTOR_SIZE))
+
+#define MAX_AES_XTS_TRANSFER_SIZE 0x1000
+
+#ifndef TRUE
+#define TRUE 1
+#endif
+
+#ifndef FALSE
+#define FALSE 0
+#endif
+
+enum fmp_crypto_algo_mode {
+ EXYNOS_FMP_BYPASS_MODE = 0,
+ EXYNOS_FMP_ALGO_MODE_AES_CBC = 1,
+ EXYNOS_FMP_ALGO_MODE_AES_XTS = 2,
+};
+
+enum fmp_crypto_key_size {
+ EXYNOS_FMP_KEY_SIZE_16 = 16,
+ EXYNOS_FMP_KEY_SIZE_32 = 32,
+};
+
+enum fmp_crypto_enc_mode {
+ EXYNOS_FMP_FILE_ENC = 0,
+ EXYNOS_FMP_DISK_ENC = 1, /* use persistent key */
+ EXYNOS_FMP_ENC_MAX
+};
+
+enum fmp_disk_key_status {
+ KEY_STORED = 0,
+ KEY_SET = 1,
+ KEY_CLEAR = 2,
+ KEY_ERROR = -1,
+};
+
+struct fmp_crypto_info {
+ /* This field's stongly aligned 'crypto_diskcipher->algo' */
+ u32 use_diskc;
+ u8 key[FMP_MAX_KEY_SIZE];
+ u32 key_size;
+ enum fmp_crypto_key_size fmp_key_size;
+ enum fmp_crypto_enc_mode enc_mode;
+ enum fmp_crypto_algo_mode algo_mode;
+ void *ctx;
+};
+
+#if defined(CONFIG_MMC_DW_EXYNOS_FMP) &&
defined(CONFIG_SCSI_UFS_EXYNOS_FMP)
+#error "FMP doesn't support muti-host"
+#elif defined(CONFIG_MMC_DW_EXYNOS_FMP)
+struct fmp_table_setting {
+ __le32 des0; /* des0 */
+#define GET_CMDQ_LENGTH(d) \
+ (((d)->des0 & 0xffff0000) >> 16)
+ __le32 des1; /* des1 */
+ __le32 des2; /* des2 */
+#define FKL BIT(26)
+#define DKL BIT(27)
+#define SET_KEYLEN(d, v) ((d)->des2 |= (uint32_t)v)
+#define SET_FAS(d, v) \
+ ((d)->des2 = ((d)->des2 & 0xcfffffff) | v << 28)
+#define SET_DAS(d, v) \
+ ((d)->des2 = ((d)->des2 & 0x3fffffff) | v << 30)
+#define GET_FAS(d) ((d)->des2 & 0x30000000)
+#define GET_DAS(d) ((d)->des2 & 0xc0000000)
+#define GET_LENGTH(d) \
+ ((d)->des2 & 0x3ffffff)
+ __le32 des3; /* des3 */
+ /* CMDQ Operation */
+#define FKL_CMDQ BIT(0)
+#define DKL_CMDQ BIT(1)
+#define SET_CMDQ_KEYLEN(d, v) ((d)->des2 |= (uint32_t)v)
+#define SET_CMDQ_FAS(d, v) \
+ ((d)->des3 = ((d)->des3 & 0xfffffff3) | v << 2)
+#define SET_CMDQ_DAS(d, v) \
+ ((d)->des3 = ((d)->des3 & 0xffffffcf) | v << 4)
+#define GET_CMDQ_FAS(d) ((d)->des3 & 0x0000000c)
+#define GET_CMDQ_DAS(d) ((d)->des3 & 0x00000030)
+ __le32 reserved0; /* des4 */
+ __le32 reserved1;
+ __le32 reserved2;
+ __le32 reserved3;
+ __le32 file_iv0; /* des8 */
+ __le32 file_iv1;
+ __le32 file_iv2;
+ __le32 file_iv3;
+ __le32 file_enckey0; /* des12 */
+ __le32 file_enckey1;
+ __le32 file_enckey2;
+ __le32 file_enckey3;
+ __le32 file_enckey4;
+ __le32 file_enckey5;
+ __le32 file_enckey6;
+ __le32 file_enckey7;
+ __le32 file_twkey0; /* des20 */
+ __le32 file_twkey1;
+ __le32 file_twkey2;
+ __le32 file_twkey3;
+ __le32 file_twkey4;
+ __le32 file_twkey5;
+ __le32 file_twkey6;
+ __le32 file_twkey7;
+ __le32 disk_iv0; /* des28 */
+ __le32 disk_iv1;
+ __le32 disk_iv2;
+ __le32 disk_iv3;
+};
+#elif defined(CONFIG_SCSI_UFS_EXYNOS_FMP)
+struct fmp_table_setting {
+ __le32 des0; /* des0 */
+#define GET_CMDQ_LENGTH(d) \
+ (((d)->des0 & 0xffff0000) >> 16)
+ __le32 des1; /* des1 */
+ __le32 des2; /* des2 */
+ __le32 des3; /* des3 */
+/* Legacy Operation */
+#define FKL BIT(26)
+#define DKL BIT(27)
+#define SET_KEYLEN(d, v) ((d)->des3 |= (uint32_t)v)
+#define SET_FAS(d, v) \
+ ((d)->des3 = ((d)->des3 & 0xcfffffff) | v << 28)
+#define SET_DAS(d, v) \
+ ((d)->des3 = ((d)->des3 & 0x3fffffff) | v << 30)
+#define GET_FAS(d) ((d)->des3 & 0x30000000)
+#define GET_DAS(d) ((d)->des3 & 0xc0000000)
+#define GET_LENGTH(d) \
+ ((d)->des3 & 0x3ffffff)
+/* CMDQ Operation */
+#define FKL_CMDQ BIT(0)
+#define DKL_CMDQ BIT(1)
+#define SET_CMDQ_KEYLEN(d, v) ((d)->des3 |= (uint32_t)v)
+#define SET_CMDQ_FAS(d, v) \
+ ((d)->des3 = ((d)->des3 & 0xfffffff3) | v << 2)
+#define SET_CMDQ_DAS(d, v) \
+ ((d)->des3 = ((d)->des3 & 0xffffffcf) | v << 4)
+#define GET_CMDQ_FAS(d) ((d)->des3 & 0x0000000c)
+#define GET_CMDQ_DAS(d) ((d)->des3 & 0x00000030)
+ __le32 file_iv0; /* des4 */
+ __le32 file_iv1; /* des5 */
+ __le32 file_iv2; /* des6 */
+ __le32 file_iv3; /* des7 */
+ __le32 file_enckey0; /* des8 */
+ __le32 file_enckey1; /* des9 */
+ __le32 file_enckey2; /* des10 */
+ __le32 file_enckey3; /* des11 */
+ __le32 file_enckey4; /* des12 */
+ __le32 file_enckey5; /* des13 */
+ __le32 file_enckey6; /* des14 */
+ __le32 file_enckey7; /* des15 */
+ __le32 file_twkey0; /* des16 */
+ __le32 file_twkey1; /* des17 */
+ __le32 file_twkey2; /* des18 */
+ __le32 file_twkey3; /* des19 */
+ __le32 file_twkey4; /* des20 */
+ __le32 file_twkey5; /* des21 */
+ __le32 file_twkey6; /* des22 */
+ __le32 file_twkey7; /* des23 */
+ __le32 disk_iv0; /* des24 */
+ __le32 disk_iv1; /* des25 */
+ __le32 disk_iv2; /* des26 */
+ __le32 disk_iv3; /* des27 */
+ __le32 reserved0; /* des28 */
+ __le32 reserved1; /* des29 */
+ __le32 reserved2; /* des30 */
+ __le32 reserved3; /* des31 */
+};
+#endif
+
+struct fmp_data_setting {
+ struct fmp_crypto_info crypt[EXYNOS_FMP_ENC_MAX];
+ struct fmp_table_setting *table;
+ bool cmdq_enabled;
+};
+
+#define EXYNOS_FMP_ALGO_MODE_MASK (0x3)
+#define EXYNOS_FMP_ALGO_MODE_TEST_OFFSET (0xf)
+#define EXYNOS_FMP_ALGO_MODE_TEST (1 << EXYNOS_FMP_ALGO_MODE_TEST_OFFSET)
+
+struct fmp_test_data {
+ char block_type[FMP_BLOCK_TYPE_NAME_LEN];
+ struct block_device *bdev;
+ sector_t sector;
+ dev_t devt;
+ uint32_t test_block_offset;
+ /* iv to submitted */
+ u8 iv[FMP_IV_SIZE_16];
+ /* diskcipher for test */
+ struct fmp_crypto_info ci;
+};
+
+struct exynos_fmp {
+ struct device *dev;
+ enum fmp_disk_key_status status_disk_key;
+ struct fmp_test_data *test_data;
+};
+
+struct fmp_request {
+ void *table;
+ bool cmdq_enabled;
+ void *iv;
+ u32 ivsize;
+};
+
+static inline void exynos_fmp_bypass(void *desc, bool cmdq_enabled)
+{
+#if defined(CONFIG_MMC_DW_EXYNOS_FMP) ||
defined(CONFIG_SCSI_UFS_EXYNOS_FMP)
+ if (cmdq_enabled) {
+ SET_CMDQ_FAS((struct fmp_table_setting *)desc, 0);
+ SET_CMDQ_DAS((struct fmp_table_setting *)desc, 0);
+ } else {
+ SET_FAS((struct fmp_table_setting *)desc, 0);
+ SET_DAS((struct fmp_table_setting *)desc, 0);
+ }
+#endif
+}
+
+#define ACCESS_CONTROL_ABORT 0x14
+
+#ifndef SMC_CMD_FMP_SECURITY
+/* For FMP/SMU Ctrl */
+#define SMC_CMD_FMP_SECURITY (0xC2001810)
+#define SMC_CMD_FMP_DISK_KEY_STORED (0xC2001820)
+#define SMC_CMD_FMP_DISK_KEY_SET (0xC2001830)
+#define SMC_CMD_FMP_DISK_KEY_CLEAR (0xC2001840)
+#define SMC_CMD_SMU (0xC2001850)
+#define SMC_CMD_FMP_SMU_RESUME (0xC2001860)
+#define SMC_CMD_FMP_SMU_DUMP (0xC2001870)
+#define SMC_CMD_UFS_LOG (0xC2001880)
+
+/* For FMP/SMU Ctrl */
+#define SMC_CMD_FMP_SECURITY (0xC2001810)
+#define SMC_CMD_FMP_DISK_KEY_STORED (0xC2001820)
+#define SMC_CMD_FMP_DISK_KEY_SET (0xC2001830)
+#define SMC_CMD_FMP_DISK_KEY_CLEAR (0xC2001840)
+#define SMC_CMD_SMU (0xC2001850)
+#define SMC_CMD_FMP_SMU_RESUME (0xC2001860)
+#define SMC_CMD_FMP_SMU_DUMP (0xC2001870)
+#define SMC_CMD_UFS_LOG (0xC2001880)
+#endif
+
+enum smu_id {
+ SMU_EMBEDDED = 0,
+ SMU_UFSCARD = 1,
+ SMU_SDCARD = 2,
+ SMU_ID_MAX,
+};
+
+enum smu_command {
+ SMU_INIT = 0,
+ SMU_SET = 1,
+ SMU_ABORT = 2,
+};
+
+/* fmp functions */
+#ifdef CONFIG_EXYNOS_FMP
+int exynos_fmp_sec_cfg(int fmp_id, int smu_id, bool init);
+int exynos_fmp_smu_abort(int id);
+int exynos_fmp_crypt_cfg(struct bio *bio, void *table_base,
+ u32 page_idx, u32 sector_unit);
+int exynos_fmp_crypt_clear(struct bio *bio, void *table_addr);
+#else
+int exynos_fmp_sec_cfg(int fmp_id, int smu_id, bool init)
+{
+ return 0;
+}
+
+int exynos_fmp_smu_abort(int id)
+{
+ return 0;
+}
+
+int exynos_fmp_crypt_cfg(struct bio *bio, void *table_base,
+ u32 page_idx, u32 sector_unit)
+{
+ return 0;
+}
+
+int exynos_fmp_crypt_clear(struct bio *bio, void *table_addr)
+{
+ return 0;
+}
+#endif
+int exynos_fmp_crypt(struct fmp_crypto_info *ci, void *priv);
+int exynos_fmp_clear(struct fmp_crypto_info *ci, void *priv);
+int exynos_fmp_setkey(struct fmp_crypto_info *ci,
+ u8 *in_key, u32 keylen, bool persistent);
+int exynos_fmp_clearkey(struct fmp_crypto_info *ci);
+void *exynos_fmp_init(struct platform_device *pdev);
+void exynos_fmp_exit(struct exynos_fmp *fmp);
+int exynos_fmp_test_crypt(struct fmp_crypto_info *ci,
+ const uint8_t *iv, uint32_t ivlen, uint8_t *src,
+ uint8_t *dst, uint32_t len, bool enc, void *priv);
+#endif /* _EXYNOS_FMP_H_ */
--
2.7.4
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
^ permalink raw reply related
* [PATCH 3/9] mmc: dw_mmc: support crypto operation
From: boojin.kim @ 2019-08-21 6:42 UTC (permalink / raw)
To: 'Jaehoon Chung', 'Ulf Hansson', linux-mmc,
linux-kernel
Cc: 'Ulf Hansson', 'Mike Snitzer', dm-devel,
'Andreas Dilger', 'Alasdair Kergon',
'Eric Biggers', linux-samsung-soc, 'Herbert Xu',
'Krzysztof Kozlowski', 'Jaehoon Chung',
'Kukjin Kim', linux-ext4, 'Chao Yu', linux-block,
linux-fscrypt, 'Jaegeuk Kim', linux-arm-kernel,
'Jens Axboe', 'Theodore Ts'o', linux-mmc,
linux-kernel, linux-f2fs-devel, linux-crypto, linux-fsdevel,
'David S. Miller'
In-Reply-To: <CGME20190821064219epcas2p28b42391923012ecc7875313b8b2b9a1a@epcas2p2.samsung.com>
This patch supports the crypto operation in mmc driver.
Two vops are added to dw_mci_drv_data for it.
The crypto_engine_cfg() is required to set crypto information such as
key and algorithm modes before I/O.
The crypto_engine_clear() is required to clear the crypto information
set in the H/W after I/O.
Cc: Jaehoon Chung <jh80.chung@samsung.com>
Cc: Ulf Hansson <ulf.hansson@linaro.org>
Signed-off-by: Boojin Kim <boojin.kim@samsung.com>
---
drivers/mmc/host/dw_mmc.c | 22 +++++++++++++++++++++-
drivers/mmc/host/dw_mmc.h | 6 ++++++
2 files changed, 27 insertions(+), 1 deletion(-)
diff --git a/drivers/mmc/host/dw_mmc.c b/drivers/mmc/host/dw_mmc.c
index eea52e2..0cdf574 100644
--- a/drivers/mmc/host/dw_mmc.c
+++ b/drivers/mmc/host/dw_mmc.c
@@ -470,6 +470,7 @@ static void dw_mci_dmac_complete_dma(void *arg)
{
struct dw_mci *host = arg;
struct mmc_data *data = host->data;
+ const struct dw_mci_drv_data *drv_data = host->drv_data;
dev_vdbg(host->dev, "DMA complete\n");
@@ -481,6 +482,9 @@ static void dw_mci_dmac_complete_dma(void *arg)
data->sg_len,
DMA_FROM_DEVICE);
+ if (drv_data && drv_data->crypto_engine_clear)
+ drv_data->crypto_engine_clear(host, host->sg_cpu, false);
+
host->dma_ops->cleanup(host);
/*
@@ -577,8 +581,10 @@ static inline int dw_mci_prepare_desc64(struct dw_mci
*host,
{
unsigned int desc_len;
struct idmac_desc_64addr *desc_first, *desc_last, *desc;
+ int i, ret;
+ const struct dw_mci_drv_data *drv_data = host->drv_data;
+ int sector_offset = 0;
u32 val;
- int i;
desc_first = desc_last = desc = host->sg_cpu;
@@ -618,6 +624,20 @@ static inline int dw_mci_prepare_desc64(struct dw_mci
*host,
desc->des4 = mem_addr & 0xffffffff;
desc->des5 = mem_addr >> 32;
+ if (drv_data && drv_data->crypto_engine_cfg) {
+ ret = drv_data->crypto_engine_cfg(host,
desc,
+ data, sg_page(&data->sg[i]),
i,
+ sector_offset, false);
+ if (ret) {
+ dev_err(host->dev,
+ "%s: fail to set
crypto(%d)\n",
+ __func__, ret);
+ return -EPERM;
+ }
+ /* mmc sector size */
+ sector_offset += desc_len / 512;
+ }
+
/* Update physical address for the next desc */
mem_addr += desc_len;
diff --git a/drivers/mmc/host/dw_mmc.h b/drivers/mmc/host/dw_mmc.h
index da5923a..b32d39b 100644
--- a/drivers/mmc/host/dw_mmc.h
+++ b/drivers/mmc/host/dw_mmc.h
@@ -563,5 +563,11 @@ struct dw_mci_drv_data {
struct mmc_ios *ios);
int (*switch_voltage)(struct mmc_host *mmc,
struct mmc_ios *ios);
+ int (*crypto_engine_cfg)(struct dw_mci *host, void
*desc,
+ struct mmc_data *data, struct page *page,
+ int page_offset, int sector_offset,
+ bool cmdq_enabled);
+ int (*crypto_engine_clear)(struct dw_mci *host,
+ void *desc, bool cmdq_enabled);
};
#endif /* _DW_MMC_H_ */
--
2.7.4
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
^ permalink raw reply related
* [PATCH 1/9] crypt: Add diskcipher
From: boojin.kim @ 2019-08-21 6:42 UTC (permalink / raw)
To: 'Herbert Xu', 'David S. Miller', linux-crypto,
linux-kernel
Cc: 'Ulf Hansson', 'Mike Snitzer', dm-devel,
'Andreas Dilger', 'Alasdair Kergon',
'Eric Biggers', linux-samsung-soc, 'Herbert Xu',
'Krzysztof Kozlowski', 'Jaehoon Chung',
'Kukjin Kim', linux-ext4, 'Chao Yu', linux-block,
linux-fscrypt, 'Jaegeuk Kim', linux-arm-kernel,
'Jens Axboe', 'Theodore Ts'o', linux-mmc,
linux-kernel, linux-f2fs-devel, linux-crypto, linux-fsdevel,
'David S. Miller'
In-Reply-To: <CGME20190821064211epcas2p43ed73f4fd126bcc5b470c9136db6aabc@epcas2p4.samsung.com>
Diskcipher supports cryptographic operations of inline crypto engines like
FMP. Inline crypto engine refers to hardware and solutions implemented
to encrypt data stored in storage device.
When encrypting using the FMP, Additional control is required
to carry and maintain the crypto information between
the encryption user(fscrypt, DM-crypt) and FMP driver.
Diskcipher provides this control.
Diskcipher is a symmetric key cipher in linux crypto API to support FMP.
FMP are registered with the cihper algorithm that uses diskcipher.
Diskcipher has three major steps.
The first step is to assign a cipher and set the key.
The second step is to pass the cipher through the BIO to the storage
driver.
The third step is to get the cipher from BIO and request a crypt
to FMP algorithm.
In the first step, encryption users such as fscrypt or dm-crypt
allocate/release a diskcipher and set key into the diskcipher.
Diskcipher provides allocate(), free(), and setkey() that are similar
to existing ciphers.
In the second step, BIO is used to pass the diskcipher to the storage
driver.
The BIO submitters such as ext4, f2fs and DM-crypt set diskcipher to BIO.
Diskcipher provides the set () API for this.
In the third step, the storage driver extracts the diskcipher from the BIO
and requests the actual encryption behavior to inline crypto engine driver.
Diskcipher provides get() and crypt() APIs for this.
Cc: Herbert Xu <herbert@gondor.apana.org.au>
Cc: David S. Miller <davem@davemloft.net>
Signed-off-by: Boojin Kim <boojin.kim@samsung.com>
---
crypto/Kconfig | 9 ++
crypto/Makefile | 1 +
crypto/diskcipher.c | 349
++++++++++++++++++++++++++++++++++++++++++++
crypto/testmgr.c | 157 ++++++++++++++++++++
include/crypto/diskcipher.h | 245 +++++++++++++++++++++++++++++++
include/linux/crypto.h | 1 +
6 files changed, 762 insertions(+)
create mode 100644 crypto/diskcipher.c
create mode 100644 include/crypto/diskcipher.h
diff --git a/crypto/Kconfig b/crypto/Kconfig
index 455a335..382d43a 100644
--- a/crypto/Kconfig
+++ b/crypto/Kconfig
@@ -1636,6 +1636,15 @@ config CRYPTO_TWOFISH_AVX_X86_64
See also:
<http://www.schneier.com/twofish.html>
+config CRYPTO_DISKCIPHER
+ bool "Diskcipher support"
+ default n
+ help
+ Disk cipher algorithm
+
+ This cipher supports the crypt operation of the block host device
+ that has inline crypto engine.
+
comment "Compression"
config CRYPTO_DEFLATE
diff --git a/crypto/Makefile b/crypto/Makefile
index 0d2cdd5..71df76a 100644
--- a/crypto/Makefile
+++ b/crypto/Makefile
@@ -165,6 +165,7 @@ obj-$(CONFIG_CRYPTO_USER_API_AEAD) += algif_aead.o
obj-$(CONFIG_CRYPTO_ZSTD) += zstd.o
obj-$(CONFIG_CRYPTO_OFB) += ofb.o
obj-$(CONFIG_CRYPTO_ECC) += ecc.o
+obj-$(CONFIG_CRYPTO_DISKCIPHER) += diskcipher.o
ecdh_generic-y += ecdh.o
ecdh_generic-y += ecdh_helper.o
diff --git a/crypto/diskcipher.c b/crypto/diskcipher.c
new file mode 100644
index 0000000..ffe95a5
--- /dev/null
+++ b/crypto/diskcipher.c
@@ -0,0 +1,349 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright (C) 2017 Samsung Electronics Co., Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#include <linux/kernel.h>
+#include <linux/blkdev.h>
+#include <linux/errno.h>
+#include <linux/module.h>
+#include <linux/seq_file.h>
+#include <linux/string.h>
+#include <linux/crypto.h>
+#include <crypto/algapi.h>
+#include <crypto/diskcipher.h>
+#include <linux/delay.h>
+#include <linux/mm_types.h>
+#include <linux/fs.h>
+#include <linux/fscrypt.h>
+
+#include "internal.h"
+
+static int crypto_diskcipher_check(struct bio *bio)
+{
+ struct crypto_diskcipher *ci = NULL;
+ struct inode *inode = NULL;
+ struct page *page = NULL;
+
+ if (!bio) {
+ pr_err("%s: doesn't exist bio\n", __func__);
+ return 0;
+ }
+
+ /* enc without fscrypt */
+ ci = bio->bi_aux_private;
+ if (!ci->inode)
+ return 0;
+ if (ci->algo == 0)
+ return 0;
+
+ page = bio->bi_io_vec[0].bv_page;
+ if (!page || PageAnon(page) || !page->mapping ||
!page->mapping->host)
+ return 0;
+
+ inode = page->mapping->host;
+ if (ci->inode != inode) {
+ pr_err("%s: fails to invalid inode\n", __func__);
+ return -EINVAL;
+ }
+
+ if (!fscrypt_has_encryption_key(inode)) {
+ pr_err("%s: fails to invalid key\n", __func__);
+ return -EINVAL;
+ }
+
+ ci = fscrypt_get_diskcipher(inode);
+ if (!ci) {
+ pr_err("%s: fails to invalid crypto info\n", __func__);
+ return -EINVAL;
+ } else if ((bio->bi_aux_private != ci) &&
+ !(bio->bi_flags & REQ_OP_DISCARD)) {
+ pr_err("%s: fails to async crypto info\n", __func__);
+ return -EINVAL;
+ }
+ return 0;
+}
+
+struct crypto_diskcipher *crypto_diskcipher_get(struct bio *bio)
+{
+ struct crypto_diskcipher *diskc = NULL;
+
+ if (!bio || !virt_addr_valid(bio)) {
+ pr_err("%s: Invalid bio:%pK\n", __func__, bio);
+ return NULL;
+ }
+ if (bio->bi_opf & REQ_CRYPT) {
+ if (bio->bi_aux_private) {
+ if (!crypto_diskcipher_check(bio)) {
+ diskc = bio->bi_aux_private;
+ } else {
+ pr_err("%s: fail to check diskcipher
bio:%pK\n",
+ __func__, bio);
+ diskc = ERR_PTR(-EINVAL);
+ }
+ } else {
+ pr_err("%s: no diskcipher on bio:%pK\n",
+ __func__, bio);
+ diskc = ERR_PTR(-EINVAL);
+ }
+ }
+
+ return diskc;
+}
+
+static inline void *bio_has_crypt(struct bio *bio)
+{
+ if (bio)
+ if (bio->bi_opf & REQ_CRYPT)
+ return bio->bi_aux_private;
+ return NULL;
+}
+
+bool crypto_diskcipher_blk_mergeble(struct bio *bio1, struct bio *bio2)
+{
+ if (!bio_has_crypt(bio1) && !bio_has_crypt(bio2))
+ return true;
+
+ if (bio_has_crypt(bio1) == bio_has_crypt(bio2)) {
+ struct crypto_diskcipher *tfm1 = bio1->bi_aux_private;
+ struct crypto_diskcipher *tfm2 = bio2->bi_aux_private;
+
+ /* no inode for DM-crypt and DM-default-key */
+ if (!tfm1->inode)
+ return true;
+
+ if ((tfm1->ivmode == IV_MODE_DUN) &&
+ (tfm2->ivmode == IV_MODE_DUN)) {
+ if (bio_dun(bio1) && bio_dun(bio2) &&
+ (bio_end_dun(bio1) == bio_dun(bio2)))
+ return true;
+ } else if ((tfm1->ivmode == IV_MODE_LBA) &&
+ (tfm2->ivmode == IV_MODE_LBA)) {
+ return true;
+ }
+ }
+ return false;
+}
+
+void crypto_diskcipher_set(struct bio *bio, struct crypto_diskcipher *tfm,
+ const struct inode *inode, u64 dun)
+{
+ if (bio && tfm) {
+ bio->bi_opf |= REQ_CRYPT;
+ bio->bi_aux_private = tfm;
+ tfm->inode = (struct inode *)inode;
+ if (dun)
+ bio->bi_iter.bi_dun = dun;
+ }
+}
+
+int crypto_diskcipher_setkey(struct crypto_diskcipher *tfm, const char
*in_key,
+ unsigned int key_len, bool persistent)
+{
+ struct crypto_tfm *base = crypto_diskcipher_tfm(tfm);
+ struct diskcipher_alg *cra =
__crypto_diskcipher_alg(base->__crt_alg);
+ int ret = -EINVAL;
+ struct inode *inode = tfm->inode;
+
+ if (cra)
+ ret = cra->setkey(tfm, in_key, key_len, persistent);
+ else
+ pr_err("%s: doesn't exist cra. base:%pK", __func__, base);
+
+ tfm->ivmode = IV_MODE_LBA;
+ if (!persistent && inode) {
+ /* check the filesystem for fscrypt */
+ if (inode->i_sb)
+ if (inode->i_sb->s_type)
+ if (!strcmp(inode->i_sb->s_type->name,
"f2fs"))
+ tfm->ivmode = IV_MODE_DUN;
+ }
+ return ret;
+}
+
+int crypto_diskcipher_clearkey(struct crypto_diskcipher *tfm)
+{
+ struct crypto_tfm *base = crypto_diskcipher_tfm(tfm);
+ struct diskcipher_alg *cra =
__crypto_diskcipher_alg(base->__crt_alg);
+ int ret = -EINVAL;
+
+ if (cra)
+ ret = cra->clearkey(tfm);
+ else
+ pr_err("%s: doesn't exist cra. base:%pK", __func__, base);
+
+ return ret;
+}
+
+int crypto_diskcipher_set_crypt(struct crypto_diskcipher *tfm, void *req)
+{
+ struct crypto_tfm *base = crypto_diskcipher_tfm(tfm);
+ struct diskcipher_alg *cra = NULL;
+ int ret = -EINVAL;
+
+ if (!base) {
+ pr_err("%s: doesn't exist base. tfm:%pK", __func__, tfm);
+ goto out;
+ }
+
+ cra = __crypto_diskcipher_alg(base->__crt_alg);
+ if (!cra) {
+ pr_err("%s: doesn't exist cra. base:%pK\n", __func__, base);
+ goto out;
+ }
+
+ ret = cra->crypt(tfm, req);
+ if (ret)
+ pr_err("%s fails ret:%d, cra:%pK\n", __func__, ret, cra);
+out:
+ return ret;
+}
+
+int crypto_diskcipher_clear_crypt(struct crypto_diskcipher *tfm, void *req)
+{
+ struct crypto_tfm *base = crypto_diskcipher_tfm(tfm);
+ struct diskcipher_alg *cra = NULL;
+ int ret = -EINVAL;
+
+ if (!base) {
+ pr_err("%s: doesn't exist base, tfm:%pK\n", __func__, tfm);
+ goto out;
+ }
+
+ cra = __crypto_diskcipher_alg(base->__crt_alg);
+ if (!cra) {
+ pr_err("%s: doesn't exist cra. base:%pK\n", __func__, base);
+ goto out;
+ }
+
+ ret = cra->clear(tfm, req);
+ if (ret)
+ pr_err("%s fails ret:%d, cra:%pK\n", __func__, ret, cra);
+out:
+ return ret;
+}
+
+int diskcipher_do_crypt(struct crypto_diskcipher *tfm,
+ struct diskcipher_test_request *req)
+{
+ struct crypto_tfm *base = crypto_diskcipher_tfm(tfm);
+ struct diskcipher_alg *cra =
__crypto_diskcipher_alg(base->__crt_alg);
+ int ret = -EINVAL;
+
+ if (!cra) {
+ pr_err("%s: doesn't exist cra. base:%pK\n", __func__, base);
+ return ret;
+ }
+
+ if (cra->do_crypt)
+ ret = cra->do_crypt(tfm, req);
+ if (ret)
+ pr_err("%s fails ret:%d", __func__, ret);
+ return ret;
+}
+
+static int crypto_diskcipher_init_tfm(struct crypto_tfm *base)
+{
+ struct crypto_diskcipher *tfm = __crypto_diskcipher_cast(base);
+ struct diskcipher_alg *alg = crypto_diskcipher_alg(tfm);
+
+ if (alg->init)
+ alg->init(tfm);
+ return 0;
+}
+
+unsigned int crypto_diskcipher_extsize(struct crypto_alg *alg)
+{
+ return alg->cra_ctxsize +
+ (alg->cra_alignmask & ~(crypto_tfm_ctx_alignment() - 1));
+}
+
+static void crypto_diskcipher_show(struct seq_file *m, struct crypto_alg
*alg)
+{
+ seq_puts(m, "type : diskcipher\n");
+}
+
+static const struct crypto_type crypto_diskcipher_type = {
+ .extsize = crypto_diskcipher_extsize,
+ .init_tfm = crypto_diskcipher_init_tfm,
+#ifdef CONFIG_PROC_FS
+ .show = crypto_diskcipher_show,
+#endif
+ .maskclear = ~CRYPTO_ALG_TYPE_MASK,
+ .maskset = CRYPTO_ALG_TYPE_MASK,
+ .type = CRYPTO_ALG_TYPE_DISKCIPHER,
+ .tfmsize = offsetof(struct crypto_diskcipher, base),
+};
+
+#define DISKC_NAME "-disk"
+#define DISKC_NAME_SIZE (5)
+#define DISKCIPHER_MAX_IO_MS (1000)
+struct crypto_diskcipher *crypto_alloc_diskcipher(const char *alg_name,
+ u32 type, u32 mask, bool force)
+{
+ int alg_name_len;
+
+ if (!force)
+ return crypto_alloc_tfm(alg_name,
+ &crypto_diskcipher_type, type, mask);
+
+ alg_name_len = strlen(alg_name);
+ if (alg_name_len + DISKC_NAME_SIZE < CRYPTO_MAX_ALG_NAME) {
+ char diskc_name[CRYPTO_MAX_ALG_NAME];
+
+ strscpy(diskc_name, alg_name, alg_name_len);
+ strcat(diskc_name, DISKC_NAME);
+ return crypto_alloc_tfm(diskc_name,
+ &crypto_diskcipher_type, type, mask);
+ }
+ return NULL;
+}
+
+void crypto_free_diskcipher(struct crypto_diskcipher *tfm)
+{
+ crypto_destroy_tfm(tfm, crypto_diskcipher_tfm(tfm));
+}
+
+int crypto_register_diskcipher(struct diskcipher_alg *alg)
+{
+ struct crypto_alg *base = &alg->base;
+
+ base->cra_type = &crypto_diskcipher_type;
+ base->cra_flags = CRYPTO_ALG_TYPE_DISKCIPHER;
+ return crypto_register_alg(base);
+}
+
+void crypto_unregister_diskcipher(struct diskcipher_alg *alg)
+{
+ crypto_unregister_alg(&alg->base);
+}
+
+int crypto_register_diskciphers(struct diskcipher_alg *algs, int count)
+{
+ int i, ret;
+
+ for (i = 0; i < count; i++) {
+ ret = crypto_register_diskcipher(algs + i);
+ if (ret)
+ goto err;
+ }
+ return 0;
+
+err:
+ for (--i; i >= 0; --i)
+ crypto_unregister_diskcipher(algs + i);
+ return ret;
+}
+
+void crypto_unregister_diskciphers(struct diskcipher_alg *algs, int count)
+{
+ int i;
+
+ for (i = count - 1; i >= 0; --i)
+ crypto_unregister_diskcipher(algs + i);
+}
diff --git a/crypto/testmgr.c b/crypto/testmgr.c
index d990eba..348dafcb 100644
--- a/crypto/testmgr.c
+++ b/crypto/testmgr.c
@@ -30,6 +30,7 @@
#include <crypto/rng.h>
#include <crypto/drbg.h>
#include <crypto/akcipher.h>
+#include <crypto/diskcipher.h>
#include <crypto/kpp.h>
#include <crypto/acompress.h>
#include <crypto/internal/simd.h>
@@ -2291,6 +2292,146 @@ static int test_aead(const char *driver, int enc,
return 0;
}
+#if defined(CONFIG_CRYPTO_DISKCIPHER)
+static int __test_diskcipher(struct crypto_diskcipher *tfm, int enc,
+ const struct cipher_testvec *template,
+ unsigned int tcount, const int align_offset)
+{
+ const char *algo =
+ crypto_tfm_alg_driver_name(crypto_diskcipher_tfm(tfm));
+ unsigned int i, j;
+ char *q;
+ struct scatterlist sg[8];
+ struct scatterlist sgout[8];
+ const char *e = (enc == ENCRYPT) ? "encryption" : "decryption";
+ void *data;
+ char iv[MAX_IVLEN];
+ char *xbuf[XBUFSIZE];
+ char *xoutbuf[XBUFSIZE];
+ int ret = -ENOMEM;
+ unsigned int ivsize = crypto_diskcipher_ivsize(tfm);
+ struct diskcipher_test_request req;
+ const char *input, *result;
+
+ if (testmgr_alloc_buf(xbuf))
+ goto out_nobuf;
+
+ if (testmgr_alloc_buf(xoutbuf))
+ goto out_nooutbuf;
+
+ j = 0;
+ for (i = 0; i < tcount; i++) {
+ if (template[i].np && !template[i].also_non_np)
+ continue;
+
+ if (template[i].fips_skip)
+ continue;
+
+ if (template[i].iv)
+ memcpy(iv, template[i].iv, ivsize);
+ else
+ memset(iv, 0, MAX_IVLEN);
+
+ input = enc ? template[i].ptext : template[i].ctext;
+ result = enc ? template[i].ctext : template[i].ptext;
+ j++;
+ ret = -EINVAL;
+ if (WARN_ON(align_offset + template[i].len > PAGE_SIZE))
+ goto out;
+
+ ret = crypto_diskcipher_setkey(tfm, template[i].key,
+ template[i].klen, 0);
+ if (ret == -ENOKEY) {
+ pr_err("alg: diskcipher: no support %d keylen for
%s. skip it\n",
+ template[i].klen, algo);
+ continue;
+ } else if (ret) {
+ pr_err("alg: diskcipher: setkey failed on test %d
for %s\n",
+ j, algo);
+ goto out;
+ }
+
+ data = xbuf[0];
+ data += align_offset;
+ memcpy(data, input, template[i].len);
+ sg_init_one(&sg[0], data, template[i].len);
+
+ data = xoutbuf[0];
+ data += align_offset;
+ sg_init_one(&sgout[0], data, template[i].len);
+
+ diskcipher_request_set_crypt(&req, sg, sgout,
+ template[i].len, iv, enc ? 1 : 0);
+ ret = diskcipher_do_crypt(tfm, &req);
+ if (ret) {
+ pr_err("alg: diskcipher: %s failed on test %d for
%s: ret=%d\n",
+ e, j, algo, -ret);
+ goto out;
+ }
+
+ q = data;
+ if (memcmp(q, result, template[i].len)) {
+ pr_err("alg: diskcipher: Test %d failed (invalid
result) on %s for %s\n",
+ j, e, algo);
+ hexdump(q, template[i].len);
+ ret = -EINVAL;
+ goto out;
+ }
+ }
+ ret = 0;
+
+out:
+ testmgr_free_buf(xoutbuf);
+out_nooutbuf:
+ testmgr_free_buf(xbuf);
+out_nobuf:
+ return ret;
+}
+
+static int test_diskcipher(struct crypto_diskcipher *tfm, int enc,
+ const struct cipher_testvec *template,
+ unsigned int tcount)
+{
+ int ret;
+
+ ret = __test_diskcipher(tfm, enc, template, tcount, 0);
+ if (ret)
+ return ret;
+
+ /* test unaligned buffers, check with one byte offset */
+ ret = __test_diskcipher(tfm, enc, template, tcount, 1);
+ if (ret)
+ return ret;
+
+ return 0;
+}
+
+static int alg_test_diskcipher(const struct alg_test_desc *desc,
+ const char *driver, u32 type, u32 mask)
+{
+ struct crypto_diskcipher *tfm;
+ const struct cipher_test_suite *suite = &desc->suite.cipher;
+ int err = 0;
+
+ tfm = crypto_alloc_diskcipher(driver, type | CRYPTO_ALG_INTERNAL,
+ mask, 0);
+ if (!tfm || IS_ERR(tfm)) {
+ pr_err("alg: diskcipher: Failed to load transform for %s:
%ld\n",
+ driver, PTR_ERR(tfm));
+ return PTR_ERR(tfm);
+ }
+
+ err = test_diskcipher(tfm, ENCRYPT, suite->vecs, suite->count);
+ if (err)
+ goto out;
+
+ err = test_diskcipher(tfm, DECRYPT, suite->vecs, suite->count);
+out:
+ crypto_free_diskcipher(tfm);
+ return err;
+}
+#endif
+
static int alg_test_aead(const struct alg_test_desc *desc, const char
*driver,
u32 type, u32 mask)
{
@@ -4029,6 +4170,14 @@ static const struct alg_test_desc alg_test_descs[] =
{
.suite = {
.cipher = __VECS(aes_cbc_tv_template)
},
+#if defined(CONFIG_CRYPTO_DISKCIPHER)
+ }, {
+ .alg = "cbc(aes)-disk",
+ .test = alg_test_diskcipher,
+ .suite = {
+ .cipher = __VECS(aes_cbc_tv_template)
+ }
+#endif
}, {
.alg = "cbc(anubis)",
.test = alg_test_skcipher,
@@ -5035,6 +5184,14 @@ static const struct alg_test_desc alg_test_descs[] =
{
.suite = {
.cipher = __VECS(aes_xts_tv_template)
}
+#if defined(CONFIG_CRYPTO_DISKCIPHER)
+ }, {
+ .alg = "xts(aes)-disk",
+ .test = alg_test_diskcipher,
+ .suite = {
+ .cipher = __VECS(aes_xts_tv_template)
+ }
+#endif
}, {
.alg = "xts(camellia)",
.generic_driver = "xts(ecb(camellia-generic))",
diff --git a/include/crypto/diskcipher.h b/include/crypto/diskcipher.h
new file mode 100644
index 0000000..a0a9879
--- /dev/null
+++ b/include/crypto/diskcipher.h
@@ -0,0 +1,245 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+/*
+ * Copyright (C) 2017 Samsung Electronics Co., Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#ifndef _DISKCIPHER_H_
+#define _DISKCIPHER_H_
+
+#include <linux/crypto.h>
+#include <linux/blk_types.h>
+
+struct diskcipher_alg;
+
+enum iv_mode {
+ IV_MODE_LBA, /* dm-dcrypt/ext4 uses it for more blk merge */
+ IV_MODE_DUN, /* f2fs should use it for garbeage colloection */
+};
+
+struct crypto_diskcipher {
+ u32 algo;
+ unsigned int ivsize;
+ struct inode *inode;
+ /* for crypto_free_req_diskcipher */
+ atomic_t status;
+ struct crypto_tfm base;
+ enum iv_mode ivmode;
+};
+
+struct diskcipher_test_request {
+ unsigned int cryptlen;
+ const u8 *iv;
+ struct scatterlist *src;
+ struct scatterlist *dst;
+ bool enc;
+};
+
+/**
+ * struct diskcipher_alg - disk cipher definition
+ * for inline crypto engine on disk host device
+ *
+ * @setkey
+ * @clearkey
+ * @crypt
+ * @clear
+ * @do_crypt
+ * @base: Common crypto API algorithm data structure.
+ *
+ * Diskcipher supports APIs to set crypto information for dm-crypt and
fscrypt
+ * And pass the crypto information to disk host device via bio.
+ * Crypt operation executes on inline crypto on disk host device.
+ */
+struct diskcipher_alg {
+ int (*init)(struct crypto_diskcipher *tfm);
+ int (*exit)(struct crypto_diskcipher *tfm);
+ int (*setkey)(struct crypto_diskcipher *tfm, const char *key,
+ u32 keylen, bool persistent);
+ int (*clearkey)(struct crypto_diskcipher *tfm);
+ int (*crypt)(struct crypto_diskcipher *tfm, void *req);
+ int (*clear)(struct crypto_diskcipher *tfm, void *req);
+ int (*do_crypt)(struct crypto_diskcipher *tfm,
+ struct diskcipher_test_request *req);
+ struct device *dev;
+ struct crypto_alg base;
+};
+
+static inline unsigned int crypto_diskcipher_ivsize(
+ struct crypto_diskcipher *tfm)
+{
+ return tfm->ivsize;
+}
+
+static inline struct crypto_tfm *crypto_diskcipher_tfm(
+ struct crypto_diskcipher *tfm)
+{
+ return &tfm->base;
+}
+
+static inline struct diskcipher_alg *__crypto_diskcipher_alg(
+ struct crypto_alg *alg)
+{
+ return container_of(alg, struct diskcipher_alg, base);
+}
+static inline struct diskcipher_alg *crypto_diskcipher_alg(
+ struct crypto_diskcipher *tfm)
+{
+ return
__crypto_diskcipher_alg(crypto_diskcipher_tfm(tfm)->__crt_alg);
+}
+
+static inline struct crypto_diskcipher *__crypto_diskcipher_cast(
+ struct crypto_tfm *tfm)
+{
+ return container_of(tfm, struct crypto_diskcipher, base);
+}
+
+int crypto_register_diskcipher(struct diskcipher_alg *alg);
+void crypto_unregister_diskcipher(struct diskcipher_alg *alg);
+int crypto_register_diskciphers(struct diskcipher_alg *algs, int count);
+void crypto_unregister_diskciphers(struct diskcipher_alg *algs, int count);
+
+#if defined(CONFIG_CRYPTO_DISKCIPHER)
+/**
+ * crypto_alloc_diskcipher() - allocate disk cipher running on disk device
+ * @alg_name: is the cra_name / name or cra_driver_name / driver name of
the
+ * skcipher cipher
+ * @type: specifies the type of the cipher
+ * @mask: specifies the mask for the cipher
+ * @force: add diskcipher postfix '-disk' on algo_name
+ *
+ * Allocate a cipher handle for an diskcipher. The returned struct
+ * crypto_diskcipher is the cipher handle that is required for any
subsequent
+ * API invocation for that diskcipher.
+ *
+ * Return: allocated cipher handle in case of success; IS_ERR() is true in
case
+ * of an error, PTR_ERR() returns the error code.
+ */
+struct crypto_diskcipher *crypto_alloc_diskcipher(const char *alg_name,
+ u32 type, u32 mask, bool force);
+
+/**
+ * crypto_free_diskcipher() - zeroize and free cipher handle
+ * @tfm: cipher handle to be freed
+ */
+void crypto_free_diskcipher(struct crypto_diskcipher *tfm);
+
+/**
+ * crypto_diskcipher_get() - get diskcipher from bio
+ * @bio: bio structure
+ */
+struct crypto_diskcipher *crypto_diskcipher_get(struct bio *bio);
+
+/**
+ * crypto_diskcipher_set() - set diskcipher to bio
+ * @bio: bio structure to contain diskcipher
+ * @tfm: cipher handle
+ *
+ * This functions set thm to bio->bi_aux_private to pass it to host driver.
+ *
+ */
+void crypto_diskcipher_set(struct bio *bio, struct crypto_diskcipher *tfm,
+ const struct inode *inode, u64 dun);
+
+/**
+ * crypto_diskcipher_setkey() - set key for cipher
+ * @tfm: cipher handle
+ * @key: buffer holding the key
+ * @keylen: length of the key in bytes
+ * @persistent: option of key storage option
+ *
+ * The caller provided key is set for the skcipher referenced by the cipher
+ * handle.
+ *
+ * Return: 0 if the setting of the key was successful; < 0 if an error
occurred
+ */
+int crypto_diskcipher_setkey(struct crypto_diskcipher *tfm, const char
*key,
+ u32 keylen, bool persistent);
+
+/**
+ * crypto_diskcipher_clearkey() - clear key
+ * @tfm: cipher handle
+ */
+int crypto_diskcipher_clearkey(struct crypto_diskcipher *tfm);
+
+/**
+ * crypto_diskcipher_set_crypt() - set crypto info for inline crypto engine
+ * @tfm: cipher handle
+ * @req: request handle. it's specific structure for inline crypt hardware
+ *
+ * Return: 0 if the setting of the key was successful; < 0 if an error
occurred
+ */
+int crypto_diskcipher_set_crypt(struct crypto_diskcipher *tfm, void *req);
+
+/**
+ * crypto_diskcipher_clear_crypt() - clear crypto info on inline crypt
hardware
+ * @tfm: cipher handle
+ * @req: request handle. it's specific structure for inline crypt hardware
+ *
+ * Return: 0 if the setting of the key was successful; < 0 if an error
occurred
+ */
+int crypto_diskcipher_clear_crypt(struct crypto_diskcipher *tfm, void
*req);
+
+/**
+ * diskcipher_do_crypt() - execute crypto for test
+ * @tfm: cipher handle
+ * @req: diskcipher_test_request handle
+ *
+ * The caller uses this function to request crypto
+ * Diskcipher_algo allocates the block area for test and then request block
I/O
+ *
+ */
+int diskcipher_do_crypt(struct crypto_diskcipher *tfm,
+ struct diskcipher_test_request *req);
+
+/**
+ * diskcipher_request_set_crypt() - fill diskcipher_test_requeust
+ * @req: request handle
+ * @src: source scatter / gather list
+ * @dst: destination scatter / gather list
+ * @cryptlen: number of bytes to process from @src
+ * @iv: IV for the cipher operation which must comply with the IV size
defined
+ * by crypto_skcipher_ivsize
+ * @enc: encrypt(1) / decrypt(0)
+ *
+ * This function allows setting of the source data and destination data
+ * scatter / gather lists.
+ *
+ * For encryption, the source is treated as the plaintext and the
+ * destination is the ciphertext. For a decryption operation, the use is
+ * reversed - the source is the ciphertext and the destination is the
plaintext.
+ */
+static inline void diskcipher_request_set_crypt(
+ struct diskcipher_test_request *req,
+ struct scatterlist *src, struct scatterlist *dst,
+ unsigned int cryptlen, void *iv, bool enc)
+{
+ req->src = src;
+ req->dst = dst;
+ req->cryptlen = cryptlen;
+ req->iv = iv;
+ req->enc = enc;
+}
+
+/**
+ * crypto_diskcipher_blk_mergeble() - check the crypt option of bios and
decide
+ * whether to merge or not
+ * @bio1: a bio to be mergeable
+ * @bio2: a bio to be mergeable
+ */
+bool crypto_diskcipher_blk_mergeble(struct bio *bio1, struct bio *bio2);
+
+#else
+
+#define crypto_alloc_diskcipher(a, b, c, d) ((void *)NULL)
+#define crypto_free_diskcipher(a) ((void)0)
+#define crypto_diskcipher_get(a) ((void *)NULL)
+#define crypto_diskcipher_set(a, b, c, d) ((void)0)
+#define crypto_diskcipher_clearkey(a) ((void)0)
+#define crypto_diskcipher_setkey(a, b, c, d) (-EINVAL)
+#define crypto_diskcipher_blk_mergeble(a, b) (0)
+#endif
+#endif /* _DISKCIPHER_H_ */
diff --git a/include/linux/crypto.h b/include/linux/crypto.h
index 19ea3a3..3a8be78 100644
--- a/include/linux/crypto.h
+++ b/include/linux/crypto.h
@@ -44,6 +44,7 @@
#define CRYPTO_ALG_TYPE_BLKCIPHER 0x00000004
#define CRYPTO_ALG_TYPE_ABLKCIPHER 0x00000005
#define CRYPTO_ALG_TYPE_SKCIPHER 0x00000005
+#define CRYPTO_ALG_TYPE_DISKCIPHER 0x00000007
#define CRYPTO_ALG_TYPE_KPP 0x00000008
#define CRYPTO_ALG_TYPE_ACOMPRESS 0x0000000a
#define CRYPTO_ALG_TYPE_SCOMPRESS 0x0000000b
--
2.7.4
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
^ permalink raw reply related
* [PATCH 0/9] Flash Memory Protector Support
From: boojin.kim @ 2019-08-21 6:42 UTC (permalink / raw)
To: 'Herbert Xu', 'David S. Miller',
'Eric Biggers', 'Theodore Y. Ts'o',
'Chao Yu', 'Jaegeuk Kim',
'Andreas Dilger', 'Theodore Ts'o', dm-devel,
'Mike Snitzer', 'Alasdair Kergon',
'Jens Axboe', 'Krzysztof Kozlowski',
'Kukjin Kim', 'Jaehoon Chung',
'Ulf Hansson', linux-crypto, linux-kernel, linux-fscrypt,
linux-mmc, linux-samsung-soc, linux-block, linux-ext4,
linux-f2fs-devel, linux-samsung-soc, linux-arm-kernel,
linux-fsdevel
In-Reply-To: <CGME20190821064206epcas2p1d1bcaae142416506bcedb3201d9a6658@epcas2p1.samsung.com>
Exynos has a H/W block called FMP (Flash Memory Protector) to protect data
stored on storage device.
FMP interworks with the storage controller to encrypt a data before writing
to the storage device and decrypt the data after reading from storage
device.
FMP is a kind of ICE (inline crypto engines), which is generally known
as being used for the above role.
To use FMP, the modification of various layers such as Fscrypt, ext4, f2fs,
DM-crypt, storage controller driver and block is required.
FMP solution introduces a new diskcipher similar to the existing skcipher
in crypo API in order to minimize the modification of these layers and
to improve the code readability.
This patchset includes the following for using FMP:
- Diskcipher and FMP are added to crypto API.
- The crypto users such as dm-crypt and fscrypt are modified to support
diskcipher.
- The bio submitters such as f2fs, ext4, dm-crypt are modified to support
diskcipher.
- Block layer is modified to pass diskcipher to storage controller driver.
- Storage controller driver is modified to support crypto operation.
Exynos FMP solution consists of Diskcipher and FMP driver.
Diskcipher is a symmetric key cipher of crypto API that supports inline
crypto engine like FMP.
FMP driver is a cipher algorithm running on diskcipher.
FMP driver registers 'cbc(aes)-disk' and 'xts(aes)-disk' algorithms to
crypto API.
FMP can be tested with various test vectors in testmgr of crypto API.
When encrypting using FMP, additional control is required to deliver and
manage encryption information between encryption users (fscrypt, DM-crypt)
and FMP drivers. Diskcipher provides this control.
The encryption using FMP is made up of 4 steps.
The first step is to assign a password and set a key.
Encryption users such as Fscrypt or DM-crypt assign diskcipher, and set key
to the diskcipher.
The second step is to deliver diskcipher that has crypto information to
storage drivers such as UFS and MMC. BIO is used to this delivery.
The BIO submitters, such as ext4, f2fs and DM-crypt, checks if there is
diskcipher in crypto configuration before issuing BIO. If there are
diskcipher, the submitter sets it to BIO.
In addition, the BIO submitter skips the task of encrypting data before BIO
and decrypting data after BIO is completed.
In the third step, the storage driver gets the diskcipher from the BIO and
requests the FMP to encrypt.
In the final step, the FMP extracts crypto information from the diskcipher
and writes it in the descriptor area allocated for FMP H/W.
The FMP H/W uses the descriptor of the storage controller to contain crypto
information. So the descriptor of storage controller should be expanded
for FMP.
Boojin Kim (9):
crypt: Add diskcipher
crypto: fmp: add Flash Memory Protector driver
mmc: dw_mmc: support crypto operation
mmc: dw_mmc-exynos: support FMP
block: support diskcipher
dm crypt: support diskcipher
fscrypt: support diskcipher
fs: ext4: support diskcipher
fs: f2fs: support diskcipher
block/bio.c | 1 +
block/blk-merge.c | 19 +-
block/bounce.c | 5 +-
crypto/Kconfig | 9 +
crypto/Makefile | 1 +
crypto/diskcipher.c | 349 +++++++++++++++++++++++
crypto/testmgr.c | 157 +++++++++++
drivers/crypto/Kconfig | 2 +
drivers/crypto/Makefile | 1 +
drivers/crypto/fmp/Kconfig | 13 +
drivers/crypto/fmp/Makefile | 1 +
drivers/crypto/fmp/fmp.c | 595
+++++++++++++++++++++++++++++++++++++++
drivers/crypto/fmp/fmp_crypt.c | 243 ++++++++++++++++
drivers/crypto/fmp/fmp_test.c | 310 ++++++++++++++++++++
drivers/crypto/fmp/fmp_test.h | 30 ++
drivers/md/dm-crypt.c | 112 +++++++-
drivers/mmc/host/Kconfig | 8 +
drivers/mmc/host/dw_mmc-exynos.c | 62 ++++
drivers/mmc/host/dw_mmc.c | 48 +++-
drivers/mmc/host/dw_mmc.h | 6 +
fs/buffer.c | 2 +
fs/crypto/bio.c | 43 ++-
fs/crypto/fscrypt_private.h | 28 +-
fs/crypto/keysetup.c | 60 +++-
fs/crypto/keysetup_v1.c | 2 +-
fs/ext4/inode.c | 39 ++-
fs/ext4/page-io.c | 8 +-
fs/ext4/readpage.c | 7 +
fs/f2fs/data.c | 98 ++++++-
fs/f2fs/f2fs.h | 2 +-
include/crypto/diskcipher.h | 245 ++++++++++++++++
include/crypto/fmp.h | 324 +++++++++++++++++++++
include/linux/bio.h | 10 +
include/linux/blk_types.h | 4 +
include/linux/bvec.h | 3 +
include/linux/crypto.h | 1 +
include/linux/fscrypt.h | 19 ++
include/uapi/linux/fscrypt.h | 2 +
tools/include/uapi/linux/fs.h | 1 +
39 files changed, 2837 insertions(+), 33 deletions(-)
create mode 100644 crypto/diskcipher.c
create mode 100644 drivers/crypto/fmp/Kconfig
create mode 100644 drivers/crypto/fmp/Makefile
create mode 100644 drivers/crypto/fmp/fmp.c
create mode 100644 drivers/crypto/fmp/fmp_crypt.c
create mode 100644 drivers/crypto/fmp/fmp_test.c
create mode 100644 drivers/crypto/fmp/fmp_test.h
create mode 100644 include/crypto/diskcipher.h
create mode 100644 include/crypto/fmp.h
--
2.7.4
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
^ permalink raw reply
* Re: [PATCH v8 2/3] fdt: add support for rng-seed
From: Ard Biesheuvel @ 2019-08-21 6:39 UTC (permalink / raw)
To: Hsin-Yi Wang
Cc: Mark Rutland, Devicetree List, Theodore Y. Ts'o, Yu Zhao,
Kees Cook, Catalin Marinas, Stephen Boyd, Will Deacon, lkml,
Mike Rapoport, Jun Yao, Miles Chen, Rob Herring, James Morse,
Andrew Murray, Andrew Morton, Laura Abbott, Frank Rowand,
moderated list:ARM/FREESCALE IMX / MXC ARM ARCHITECTURE,
Robin Murphy
In-Reply-To: <CAJMQK-hdYz+pW5QL41nXkZAX1qiRynaWg7cne48qCaQsuPrSCg@mail.gmail.com>
On Wed, 21 Aug 2019 at 08:57, Hsin-Yi Wang <hsinyi@chromium.org> wrote:
>
> Then we'd still use add_device_randomness() in case that bootloader
> provides weak entropy.
>
(please don't top post)
Whether to trust the firmware provided entropy is a policy decision,
and typically, we try to avoid dictating policy in the kernel, and
instead, we try to provide a sane default but give the user control
over it.
So in this case, we should probably introduce
add_firmware_randomness() with a Kconfig/cmdline option pair to decide
whether it should be trusted or not (or reuse the one we have for
trusting RDRAND etc)
> On Tue, Aug 20, 2019 at 7:14 PM Ard Biesheuvel
> <ard.biesheuvel@linaro.org> wrote:
> >
> > On Tue, 20 Aug 2019 at 10:43, Hsin-Yi Wang <hsinyi@chromium.org> wrote:
> > >
> > > Hi Ted,
> > >
> > > Thanks for raising this question.
> > >
> > > For UEFI based system, they have a config table that carries rng seed
> > > and can be passed to device randomness. However, they also use
> > > add_device_randomness (not sure if it's the same reason that they
> > > can't guarantee _all_ bootloader can be trusted)
> >
> > The config table is actually a Linux invention: it is populated by the
> > EFI stub code (which is part of the kernel) based on the output of a
> > call into the EFI_RNG_PROTOCOL, which is defined in the UEFI spec, but
> > optional and not widely available.
> >
> > I have opted for add_device_randomness() since there is no way to
> > establish the quality level of the output of EFI_RNG_PROTOCOL, and so
> > it is currently only used to prevent the bootup state of the entropy
> > pool to be too predictable, and the output does not contribute to the
> > entropy estimate kept by the RNG core.
> >
> >
> > > This patch is to let DT based system also have similar features, which
> > > can make initial random number stronger. (We only care initial
> > > situation here, since more entropy would be added to kernel as time
> > > goes on )
> > >
> > > Conservatively, we can use add_device_randomness() as well, which
> > > would pass buffer to crng_slow_load() instead of crng_fast_load().
> > > But I think we should trust bootloader here. Whoever wants to use this
> > > feature should make sure their bootloader can pass valid (random
> > > enough) seeds. If they are not sure, they can just don't add the
> > > property to DT.
> >
> > It is the firmware that adds the property to the DT, not the user.
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
^ permalink raw reply
* Re: [PATCH 5/8] soc: ti: omap-prm: add omap4 PRM data
From: Tero Kristo @ 2019-08-21 6:38 UTC (permalink / raw)
To: Suman Anna, ssantosh, linux-arm-kernel, linux-omap, robh+dt
Cc: tony, devicetree
In-Reply-To: <ed0ec707-ddea-cbfa-ecdf-99faeb770f3f@ti.com>
On 20.8.2019 20.23, Suman Anna wrote:
> On 8/20/19 2:52 AM, Tero Kristo wrote:
>> On 20.8.2019 2.08, Suman Anna wrote:
>>> On 8/7/19 2:48 AM, Tero Kristo wrote:
>>>> Add PRM data for omap4 family of SoCs.
>>>>
>>>> Signed-off-by: Tero Kristo <t-kristo@ti.com>
>>>> ---
>>>> drivers/soc/ti/omap_prm.c | 20 ++++++++++++++++++++
>>>> 1 file changed, 20 insertions(+)
>>>>
>>>> diff --git a/drivers/soc/ti/omap_prm.c b/drivers/soc/ti/omap_prm.c
>>>> index 870515e3..9b8d5945 100644
>>>> --- a/drivers/soc/ti/omap_prm.c
>>>> +++ b/drivers/soc/ti/omap_prm.c
>>>> @@ -54,7 +54,27 @@ struct omap_reset_data {
>>>> #define OMAP_PRM_NO_RSTST BIT(0)
>>>> +struct omap_prm_data omap4_prm_data[] = {
>>>
>>> static const
>>
>> Will fix this and rest of the similar comments.
>>
>> -Tero
>>
>>>
>>> regards
>>> Suman
>>>
>>>> + { .name = "mpu", .base = 0x4a306300, .pwstst = 0x4 },
>>>> + { .name = "tesla", .base = 0x4a306400, .pwstst = 0x4, .rstctl =
>>>> 0x10, .rstst = 0x14 },
>>>> + { .name = "abe", .base = 0x4a306500, .pwstst = 0x4 },
>>>> + { .name = "always_on_core", .base = 0x4a306600, .pwstst = 0x4 },
>>>> + { .name = "core", .base = 0x4a306700, .pwstst = 0x4, .rstctl =
>>>> 0x210, .rstst = 0x214 },
>>>> + { .name = "ivahd", .base = 0x4a306f00, .pwstst = 0x4, .rstctl =
>>>> 0x10, .rstst = 0x14 },
>>>> + { .name = "cam", .base = 0x4a307000, .pwstst = 0x4 },
>>>> + { .name = "dss", .base = 0x4a307100, .pwstst = 0x4 },
>>>> + { .name = "gfx", .base = 0x4a307200, .pwstst = 0x4 },
>>>> + { .name = "l3init", .base = 0x4a307300, .pwstst = 0x4 },
>>>> + { .name = "l4per", .base = 0x4a307400, .pwstst = 0x4 },
>>>> + { .name = "cefuse", .base = 0x4a307600, .pwstst = 0x4 },
>>>> + { .name = "wkup", .base = 0x4a307700, .pwstst = 0x4 },
>>>> + { .name = "emu", .base = 0x4a307900, .pwstst = 0x4 },
>>>> + { .name = "device", .base = 0x4a307b00, .rstctl = 0x0, .rstst =
>>>> 0x4 },
>
> So, looks like you are using pwstctrl as 0 by default, but some of them
> will neither have pwstctrl or pwstst like "device" PRM here. Is the plan
> to use -1 for the fields, or a flags field?
Multiple paths are possible, I will see what makes most sense once I
implement it.
-Tero
>
> regards
> Suman
>
>>>> + { },
>>>> +};
>>>> +
>>>> static const struct of_device_id omap_prm_id_table[] = {
>>>> + { .compatible = "ti,omap4-prm-inst", .data = omap4_prm_data },
>>>> { },
>>>> };
>>>>
>>>
>>
>> --
>
--
Texas Instruments Finland Oy, Porkkalankatu 22, 00180 Helsinki. Y-tunnus/Business ID: 0615521-4. Kotipaikka/Domicile: Helsinki
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
^ permalink raw reply
* Re: [PATCH] efi/arm: fix allocation failure when reserving the kernel base
From: Ard Biesheuvel @ 2019-08-21 6:35 UTC (permalink / raw)
To: Chester Lin
Cc: Juergen Gross, linux-efi@vger.kernel.org,
guillaume.gardet@arm.com, linux-kernel@vger.kernel.org,
Russell King - ARM Linux admin, Joey Lee, geert@linux-m68k.org,
ren_guo@c-sky.com, Gary Lin, akpm@linux-foundation.org,
rppt@linux.ibm.com, mingo@kernel.org,
linux-arm-kernel@lists.infradead.org
In-Reply-To: <20190821061027.GA2828@linux-8mug>
On Wed, 21 Aug 2019 at 09:11, Chester Lin <clin@suse.com> wrote:
>
> On Tue, Aug 20, 2019 at 03:28:25PM +0300, Ard Biesheuvel wrote:
> > On Tue, 20 Aug 2019 at 14:56, Russell King - ARM Linux admin
> > <linux@armlinux.org.uk> wrote:
> > >
> > > On Fri, Aug 02, 2019 at 05:38:54AM +0000, Chester Lin wrote:
> > > > diff --git a/arch/arm/mm/mmu.c b/arch/arm/mm/mmu.c
> > > > index f3ce34113f89..909b11ba48d8 100644
> > > > --- a/arch/arm/mm/mmu.c
> > > > +++ b/arch/arm/mm/mmu.c
> > > > @@ -1184,6 +1184,9 @@ void __init adjust_lowmem_bounds(void)
> > > > phys_addr_t block_start = reg->base;
> > > > phys_addr_t block_end = reg->base + reg->size;
> > > >
> > > > + if (memblock_is_nomap(reg))
> > > > + continue;
> > > > +
> > > > if (reg->base < vmalloc_limit) {
> > > > if (block_end > lowmem_limit)
> > > > /*
> > >
> > > I think this hunk is sane - if the memory is marked nomap, then it isn't
> > > available for the kernel's use, so as far as calculating where the
> > > lowmem/highmem boundary is, it effectively doesn't exist and should be
> > > skipped.
> > >
> >
> > I agree.
> >
> > Chester, could you explain what you need beyond this change (and my
> > EFI stub change involving TEXT_OFFSET) to make things work on the
> > RPi2?
> >
>
> Hi Ard,
>
> In fact I am working with Guillaume to try booting zImage kernel and openSUSE
> from grub2.04 + arm32-efistub so that's why we get this issue on RPi2, which is
> one of the test machines we have. However we want a better solution for all
> cases but not just RPi2 since we don't want to affect other platforms as well.
>
Thanks Chester, but that doesn't answer my question.
Your fix is a single patch that changes various things that are only
vaguely related. We have already identified that we need to take
TEXT_OFFSET (minus some space used by the swapper page tables) into
account into the EFI stub if we want to ensure compatibility with many
different platforms, and as it turns out, this applies not only to
RPi2 but to other platforms as well, most notably the ones that
require a TEXT_OFFSET of 0x208000, since they also have reserved
regions at the base of RAM.
My question was what else we need beyond:
- the EFI stub TEXT_OFFSET fix [0]
- the change to disregard NOMAP memblocks in adjust_lowmem_bounds()
- what else???
[0] https://git.kernel.org/pub/scm/linux/kernel/git/efi/efi.git/commit/?h=next&id=0eb7bad595e52666b642a02862ad996a0f9bfcc0
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
^ permalink raw reply
* Re: [PATCH] efi/arm: fix allocation failure when reserving the kernel base
From: Chester Lin @ 2019-08-21 6:10 UTC (permalink / raw)
To: Ard Biesheuvel
Cc: Juergen Gross, Joey Lee, linux-efi@vger.kernel.org,
guillaume.gardet@arm.com, linux-kernel@vger.kernel.org,
Russell King - ARM Linux admin, rppt@linux.ibm.com, Chester Lin,
geert@linux-m68k.org, ren_guo@c-sky.com, Gary Lin,
akpm@linux-foundation.org, mingo@kernel.org,
linux-arm-kernel@lists.infradead.org
In-Reply-To: <CAKv+Gu_0wFw5Mjpdw7BEY7ewgetNgU=Ff1uvAsn0iHmJouyKqw@mail.gmail.com>
On Tue, Aug 20, 2019 at 03:28:25PM +0300, Ard Biesheuvel wrote:
> On Tue, 20 Aug 2019 at 14:56, Russell King - ARM Linux admin
> <linux@armlinux.org.uk> wrote:
> >
> > On Fri, Aug 02, 2019 at 05:38:54AM +0000, Chester Lin wrote:
> > > diff --git a/arch/arm/mm/mmu.c b/arch/arm/mm/mmu.c
> > > index f3ce34113f89..909b11ba48d8 100644
> > > --- a/arch/arm/mm/mmu.c
> > > +++ b/arch/arm/mm/mmu.c
> > > @@ -1184,6 +1184,9 @@ void __init adjust_lowmem_bounds(void)
> > > phys_addr_t block_start = reg->base;
> > > phys_addr_t block_end = reg->base + reg->size;
> > >
> > > + if (memblock_is_nomap(reg))
> > > + continue;
> > > +
> > > if (reg->base < vmalloc_limit) {
> > > if (block_end > lowmem_limit)
> > > /*
> >
> > I think this hunk is sane - if the memory is marked nomap, then it isn't
> > available for the kernel's use, so as far as calculating where the
> > lowmem/highmem boundary is, it effectively doesn't exist and should be
> > skipped.
> >
>
> I agree.
>
> Chester, could you explain what you need beyond this change (and my
> EFI stub change involving TEXT_OFFSET) to make things work on the
> RPi2?
>
Hi Ard,
In fact I am working with Guillaume to try booting zImage kernel and openSUSE
from grub2.04 + arm32-efistub so that's why we get this issue on RPi2, which is
one of the test machines we have. However we want a better solution for all
cases but not just RPi2 since we don't want to affect other platforms as well.
Regards,
Chester
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
^ permalink raw reply
* Re: [linux-sunxi] [PATCH v5 09/15] clk: sunxi-ng: h6: Allow I2S to change parent rate
From: Chen-Yu Tsai @ 2019-08-21 6:01 UTC (permalink / raw)
To: Code Kipper
Cc: Jernej Skrabec, Linux-ALSA, linux-kernel, Liam Girdwood,
Andrea Venturi (pers), linux-sunxi, Mark Brown, Maxime Ripard,
linux-arm-kernel
In-Reply-To: <CAEKpxBnxf=iejk887A7qFkzt3BXVxiRS1PeA45aZYR9DsBAU4Q@mail.gmail.com>
On Wed, Aug 21, 2019 at 1:52 PM Code Kipper <codekipper@gmail.com> wrote:
>
> Thanks....I've added to my next patch series but if you could add it
> when applying that would be great.
Please reply with an explicit SoB to put it on the record.
ChenYu
> BR,
> CK
>
> On Wed, 21 Aug 2019 at 06:07, Chen-Yu Tsai <wens@csie.org> wrote:
> >
> > On Wed, Aug 14, 2019 at 2:09 PM <codekipper@gmail.com> wrote:
> > >
> > > From: Jernej Skrabec <jernej.skrabec@siol.net>
> > >
> > > I2S doesn't work if parent rate couldn't be change. Difference between
> > > wanted and actual rate is too big.
> > >
> > > Fix this by adding CLK_SET_RATE_PARENT flag to I2S clocks.
> > >
> > > Signed-off-by: Jernej Skrabec <jernej.skrabec@siol.net>
> >
> > This lacks your SoB. Please reply and I can add it when applying.
> >
> > ChenYu
>
> --
> You received this message because you are subscribed to the Google Groups "linux-sunxi" group.
> To unsubscribe from this group and stop receiving emails from it, send an email to linux-sunxi+unsubscribe@googlegroups.com.
> To view this discussion on the web, visit https://groups.google.com/d/msgid/linux-sunxi/CAEKpxBnxf%3Diejk887A7qFkzt3BXVxiRS1PeA45aZYR9DsBAU4Q%40mail.gmail.com.
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
^ permalink raw reply
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox