On 8/2/19 2:48 PM, Jan Kiszka wrote:
> On 02.08.19 14:33, Ralf Ramsauer wrote:
>> ACPI tables aren't available if Linux runs as guest of the hypervisor
>> Jailhouse. This makes the 8250 driver probe for all platform UARTs as
>> it assumes that all platform are present in case of !ACPI. Jailhouse
>> will stop execution of Linux guest due to port access violation.
>>
>> So far, these access violations could be solved by tuning the
>> 8250.nr_uarts parameter but it has limitations: We can, e.g., only map
>> consecutive platform UARTs to Linux, and only in the sequence 0x3f8,
>> 0x2f8, 0x3e8, 0x2e8.
>>
>> Beginning from setup_data version 2, Jailhouse will place information of
>> available platform UARTs in setup_data. This allows for selective
>> activation of platform UARTs.
>>
>> This patch queries the setup_data version and activates only available
>> UARTS. It comes with backward compatibility, and will still support
>> older setup_data versions. In this case, Linux falls back to the old
>> behaviour.
>>
>> Signed-off-by: Ralf Ramsauer <[email protected]>
>> ---
>>  arch/x86/include/uapi/asm/bootparam.h |  1 +
>>  arch/x86/kernel/jailhouse.c           | 74 ++++++++++++++++++++++++---
>>  2 files changed, 69 insertions(+), 6 deletions(-)
>>
>> diff --git a/arch/x86/include/uapi/asm/bootparam.h 
>> b/arch/x86/include/uapi/asm/bootparam.h
>> index a06cbf019744..2d6a40cbf3df 100644
>> --- a/arch/x86/include/uapi/asm/bootparam.h
>> +++ b/arch/x86/include/uapi/asm/bootparam.h
>> @@ -146,6 +146,7 @@ struct jailhouse_setup_data {
>>      __u32   apic_khz;
>>      __u8    standard_ioapic;
>>      __u8    cpu_ids[255];
>> +    __u32   flags;
>>  } __attribute__((packed));
>>  
>>  /* The so-called "zeropage" */
>> diff --git a/arch/x86/kernel/jailhouse.c b/arch/x86/kernel/jailhouse.c
>> index 108c48d0d40e..3b73647b2456 100644
>> --- a/arch/x86/kernel/jailhouse.c
>> +++ b/arch/x86/kernel/jailhouse.c
>> @@ -11,6 +11,7 @@
>>  #include <linux/acpi_pmtmr.h>
>>  #include <linux/kernel.h>
>>  #include <linux/reboot.h>
>> +#include <linux/serial_8250.h>
>>  #include <asm/apic.h>
>>  #include <asm/cpu.h>
>>  #include <asm/hypervisor.h>
>> @@ -20,6 +21,10 @@
>>  #include <asm/reboot.h>
>>  #include <asm/setup.h>
>>  
>> +#define SETUP_DATA_FLAGS_PERMIT_PCUART(n) (1 << (n))
>> +#define SETUP_DATA_FLAGS_HAS_PCUART(flags, n) \
>> +    !!(flags & SETUP_DATA_FLAGS_PERMIT_PCUART(n))
>> +
>>  static __initdata struct jailhouse_setup_data setup_data;
>>  static unsigned int precalibrated_tsc_khz;
>>  
>> @@ -76,11 +81,13 @@ static void __init jailhouse_get_smp_config(unsigned int 
>> early)
>>              .type = IOAPIC_DOMAIN_STRICT,
>>              .ops = &mp_ioapic_irqdomain_ops,
>>      };
>> +#ifdef CONFIG_SERIAL_8250
>>      struct mpc_intsrc mp_irq = {
>>              .type = MP_INTSRC,
>>              .irqtype = mp_INT,
>>              .irqflag = MP_IRQPOL_ACTIVE_HIGH | MP_IRQTRIG_EDGE,
>>      };
>> +#endif
>>      unsigned int cpu;
>>  
>>      jailhouse_x2apic_init();
>> @@ -97,12 +104,16 @@ static void __init jailhouse_get_smp_config(unsigned 
>> int early)
>>      if (setup_data.standard_ioapic) {
>>              mp_register_ioapic(0, 0xfec00000, gsi_top, &ioapic_cfg);
>>  
>> -            /* Register 1:1 mapping for legacy UART IRQs 3 and 4 */
>> -            mp_irq.srcbusirq = mp_irq.dstirq = 3;
>> -            mp_save_irq(&mp_irq);
>> +#ifdef CONFIG_SERIAL_8250
>> +            if (setup_data.version < 2) {
>> +                    /* Register 1:1 mapping for legacy UART IRQs 3 and 4 */
>> +                    mp_irq.srcbusirq = mp_irq.dstirq = 3;
>> +                    mp_save_irq(&mp_irq);
>>  
>> -            mp_irq.srcbusirq = mp_irq.dstirq = 4;
>> -            mp_save_irq(&mp_irq);
>> +                    mp_irq.srcbusirq = mp_irq.dstirq = 4;
>> +                    mp_save_irq(&mp_irq);
>> +            }
>> +#endif
>>      }
>>  }
>>  
>> @@ -135,6 +146,42 @@ static int __init jailhouse_pci_arch_init(void)
>>      return 0;
>>  }
>>  
>> +#ifdef CONFIG_SERIAL_8250
>> +static const u16 pcuart_base[] = {
>> +    0x3f8,
>> +    0x2f8,
>> +    0x3e8,
>> +    0x2e8,
>> +};
>> +
>> +static void jailhouse_serial_fixup(int port, struct uart_port *up,
>> +                               u32 *capabilites)
>> +{
>> +    struct mpc_intsrc mp_irq = {
>> +            .type = MP_INTSRC,
>> +            .irqtype = mp_INT,
>> +            .irqflag = MP_IRQPOL_ACTIVE_HIGH | MP_IRQTRIG_EDGE,
>> +    };
>> +    unsigned int n;
>> +
>> +    for (n = 0; n < ARRAY_SIZE(pcuart_base); n++) {
>> +            if (pcuart_base[n] != up->iobase)
>> +                    continue;
>> +
>> +            if (SETUP_DATA_FLAGS_HAS_PCUART(setup_data.flags, n)) {
>> +                    pr_info("Enabling UART%u (port 0x%lx)\n", n,
>> +                            up->iobase);
>> +                    mp_irq.srcbusirq = mp_irq.dstirq = up->irq;
>> +                    mp_save_irq(&mp_irq);
>> +            } else {
>> +                    /* Deactivate UART if access isn't allowed */
>> +                    up->iobase = 0;
>> +            }
>> +            break;
>> +    }
>> +}
>> +#endif
>> +
>>  static void __init jailhouse_init_platform(void)
>>  {
>>      u64 pa_data = boot_params.hdr.setup_data;
>> @@ -162,8 +209,12 @@ static void __init jailhouse_init_platform(void)
>>              memcpy(&header, mapping, sizeof(header));
>>              early_memunmap(mapping, sizeof(header));
>>  
>> +            /*
>> +             * Version 2 extends version 1 by four byte. We still do
>> +             * support version 1.
>> +             */
>>              if (header.type == SETUP_JAILHOUSE &&
>> -                header.len >= sizeof(setup_data)) {
>> +                header.len >= (sizeof(setup_data) - 4)) {
> 
> Hmm, looking at this again, maybe it's better to have struct setup_data_v1
> inside setup_data, instead of a magic "- 4".

Thanks for mentioning. But that's probably not enough. From now on, the
size we copy from setup_data depends on the version. I forgot to respect
that.

And this eventually brings me to the point that we need proper version
handling.

> 
>>                      pa_data += offsetof(struct setup_data, data);
>>  
>>                      mapping = early_memremap(pa_data, sizeof(setup_data));
>> @@ -195,6 +246,17 @@ static void __init jailhouse_init_platform(void)
>>       * are none in a non-root cell.
>>       */
>>      disable_acpi();
>> +
>> +#ifdef CONFIG_SERIAL_8250
>> +    /* Since setup_data.version 2 we have flags that indicate availability
>> +     * of platform UARTs.
>> +     *
>> +     * In case of version 1, we don't know which UARTs belong Linux. In
>> +     * this case, unconditionally register 1:1 mapping for legacy UART IRQs
>> +     * 3 and 4 */
>> +    if (setup_data.version > 1)
>> +            serial8250_set_isa_configurator(jailhouse_serial_fixup);
>> +#endif
>>  }
>>  
>>  bool jailhouse_paravirt(void)
>>
> 
> When addressing the above, you can add my
> 
> Reviewed-by: Jan Kiszka <[email protected]>

Thanks, but I guess this will now become two patches. The first one for
proper version handling, the second one that implements setup_data
version 2.

Logically, the second patch will stay the same, but there's probably too
much noise from the first patch to keep your Reviewed-by.

  Ralf

-- 
You received this message because you are subscribed to the Google Groups 
"Jailhouse" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to [email protected].
To view this discussion on the web visit 
https://groups.google.com/d/msgid/jailhouse-dev/d08c2103-f24b-4dd4-2f21-aec6fd068921%40oth-regensburg.de.

Reply via email to