lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  linux-cve-announce  PHC 
Open Source and information security mailing list archives
 
Hash Suite: Windows password security audit tool. GUI, reports in PDF.
[<prev] [next>] [<thread-prev] [day] [month] [year] [list]
Date:   Mon, 03 Jul 2017 13:32:30 -0700 (PDT)
From:   Palmer Dabbelt <palmer@...belt.com>
To:     tglx@...utronix.de
CC:     linux-kernel@...r.kernel.org
Subject:     Re: [PATCH 1/2] irqchip: RISC-V Local Interrupt Controller Driver

On Mon, 03 Jul 2017 04:13:34 PDT (-0700), tglx@...utronix.de wrote:
> On Thu, 29 Jun 2017, Palmer Dabbelt wrote:
>> On Wed, 28 Jun 2017 13:47:40 PDT (-0700), tglx@...utronix.de wrote:
>> In this case the software interrupt is to handle IPIs, so it doesn't really
>> make any sense to handle one without SMP.  I'm OK with just warning, though, as
>> the IPIs are just for TLB shootdowns so skipping one on a non-SMP system seems
>> safe.
>
> Indeed.
>
>> >> +static void riscv_irq_mask(struct irq_data *d)
>> >> +{
>> >> +	struct riscv_irq_data *data = irq_data_get_irq_chip_data(d);
>> >> +
>> >> +	BUG_ON(smp_processor_id() != data->hart);
>> >
>> > Crashing the machine is the last resort if there is no chance to handle a
>> > situation gracefully. Something like
>> >
>> > 	if (WARN_ON_ONCE(smp_processor_id() != data->hart))
>> > 		do_something_sensible();
>> > 	else
>> > 		.....
>> >
>> > might at least keep the machine halfways functional for debugging.
>>
>> In this case I think BUG_ON is the only sane thing to do.  I've gone and added
>> a comment that explains what's going on here
>>
>>   diff --git a/drivers/irqchip/irq-riscv-intc.c b/drivers/irqchip/irq-riscv-intc.c
>>   index 7e55fe57e95f..3dd421ade128 100644
>>   --- a/drivers/irqchip/irq-riscv-intc.c
>>   +++ b/drivers/irqchip/irq-riscv-intc.c
>>   @@ -97,6 +97,14 @@ static const struct irq_domain_ops riscv_irqdomain_ops = {
>>           .xlate  = irq_domain_xlate_onecell,
>>    };
>>
>>   +/*
>>   + * On RISC-V systems local interrupts are masked or unmasked by writing the SIE
>>   + * (Supervisor Interrupt Enable) CSR.  As CSRs can only be written on the local
>>   + * hart, these functions can only be called on the hart that cooresponds to the
>>   + * IRQ chip.  They are only called internally to this module, so they BUG_ON if
>>   + * this condition is violated rather than attempting to handle the error by
>>   + * forwarding to the target hart, as that's already expected to have been done.
>>   + */
>>    static void riscv_irq_mask(struct irq_data *d)
>>    {
>>           struct riscv_irq_data *data = irq_data_get_irq_chip_data(d);
>>
>> I think there's three options here:
>>
>>  * BUG_ON like we do.
>>  * Attempt to jump to the correct hart to set the CSR, but since we just did
>>    that I don't really see why it would work the second time.
>>  * Provide a warning and then ignore {un,}masking the IRQ, but that seems
>>    dangerous.
>>
>> I can change it to a warning if you think it's better.
>
> With a coherent explanation why a BUG_ON() is the right thing to do, the
> BUG_ON can stay.
>
>>   diff --git a/drivers/irqchip/irq-riscv-intc.c b/drivers/irqchip/irq-riscv-intc.c
>>   index 3dd421ade128..b2643f7131ff 100644
>>   --- a/drivers/irqchip/irq-riscv-intc.c
>>   +++ b/drivers/irqchip/irq-riscv-intc.c
>>   @@ -137,9 +137,13 @@ static void riscv_irq_enable(struct irq_data *d)
>>           struct riscv_irq_data *data = irq_data_get_irq_chip_data(d);
>>
>>           /*
>>   -        * There are two phases to setting up an interrupt: first we set a bit
>>   -        * in this bookkeeping structure, which is used by trap_init to
>>   -        * initialize SIE for each hart as it comes up.
>>   +        * When booting a RISC-V system, procesors can come online at any time.
>
> Not so much at any time. The kernel orchestrates that.
>
>>   +        * Interrupts can only be enabled or disabled by writing a CSR on the
>>   +        * hart that cooresponds to that interrupt controller, but CSRs can
>>   +        * only be written locally.  In order to avoid waiting a long time for
>>   +        * a hart to boot, we instead collect the interrupts to be enabled upon
>>   +        * booting a hart in this bookkeeping structure, which is used by
>>   +        * trap_init to initialize SIE for each hart as it comes up.
>>            */
>>           atomic_long_or((1 << (long)d->hwirq),
>>                          &per_cpu(riscv_early_sie, data->hart));
>
> That still does not answer the question WHY an interrupt for a not
> available CPU would be enabled in the first place.
>
>> >> +static int riscv_intc_init(struct device_node *node, struct device_node *parent)
>> >> +{
>> >> +	int hart;
>> >> +	struct riscv_irq_data *data;
>> >> +
>> >> +	if (parent)
>> >> +		return 0;
>> >> +
>> >> +	hart = riscv_of_processor_hart(node->parent);
>> >> +	if (hart < 0) {
>> >> +		/* If a hart is disabled, create a no-op irq domain.  Devices
>> >> +		 * may still have interrupts connected to those harts.  This is
>> >> +		 * not wrong... unless they actually load a driver that needs
>> >> +		 * it!
>> >> +		 */
>> >> +		irq_domain_add_linear(
>> >> +			node,
>> >> +			8*sizeof(uintptr_t),
>> >> +			&riscv_irqdomain_ops_noop,
>> >> +			node->parent);
>> >> +		return 0;
>> >
>> > I have a hard time to understand the logic here. Why do you need an
>> > interrupt domain for something which does not exist? That does not make any
>> > sense.
>>
>> I think this is best explained as a comment, which I've added
>>
>>   diff --git a/drivers/irqchip/irq-riscv-intc.c b/drivers/irqchip/irq-riscv-intc.c
>>   index a62a1f04198e..52db58a94bdc 100644
>>   --- a/drivers/irqchip/irq-riscv-intc.c
>>   +++ b/drivers/irqchip/irq-riscv-intc.c
>>   @@ -178,6 +178,32 @@ static void riscv_irq_disable(struct irq_data *d)
>>                                            true);
>>    }
>>
>>   +/*
>>   + * This "no op" interrupt handler deals with harts that for some reason exist
>>   + * but can't actually run Linux.  Examples of these sorts of harts include:
>>   + * - Harts that don't report an "okay" status, presumably because of a hardware
>>   + *   fault.
>>   + * - Harts with an ID larger than NR_CPUS.
>>   + * - Harts with an ISA we don't understand.
>>   + *
>>   + * Interrupts targeted to these harts won't even actually be seen by Linux, as
>>   + * there's no code running to ever receive the interrupt.  If this is an
>>   + * invalid system configuration then there's nothing we can really do about it,
>>   + * but we expect these configurations to usually be valid.
>
> But what would enable such interrupts in the first place? The device whose
> interrupt is routed into nirwana is going to be non-functional. See below.
>
>>   + * For example, we generally allow the PLIC to route interrupts to every hart
>>   + * in the system via the local interrupt controller on every hart.
>
> That's fine, but you really want to control that via the interrupt affinity
> mechanism and not by blindly routing every interrupt to every possible CPU
> in the system. That mechanism is there for a reason.
>
>>   + * When Linux
>>   + * is built without CONFIG_SMP this still allows for a working system, as the
>>   + * single enabled hart can handle every device interrupt in the system.
>
> Well, that's how it should be. But that still does not require to handle
> anything which is not usable.
>
>>   + * It is
>>   + * possible to build a PLIC that doesn't allow interrupts to be routed to the
>>   + * first hart to boot.  If for some reason the PLIC was instantiated in this
>>   + * manner then whatever devices could not be directed to the first hart to boot
>>   + * would be unusable on non-CONFIG_SMP kernels, but as we can't change the PLIC
>>   + * hardware there's nothing we can do about that.
>>   + *
>>   + * In order to avoid the complexity of having unmapped IRQ domains, we instead
>>   + * just install the noop IRQ handler in domains we can't handle.
>
> What's complex about that? If a device driver tries to request an unmapped
> irq then the request will fail and the driver can act accordingly.
>
> Silently pretending success and then letting the user bang his head against
> the wall is definitely the worst thing you can do.

OK, we'll do it that way.  I'll submit another patch set soon.

Thanks!

Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ