firmware: google: Probe for a GSMI handler in firmware
authorArthur Heymans <arthur@aheymans.xyz>
Mon, 18 Nov 2019 10:19:31 +0000 (11:19 +0100)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Tue, 14 Jan 2020 20:46:48 +0000 (21:46 +0100)
Currently this driver is loaded if the DMI string matches coreboot
and has a proper smi_command in the ACPI FADT table, but a GSMI handler in
SMM is an optional feature in coreboot.

So probe for a SMM GSMI handler before initializing the driver.
If the smihandler leaves the calling argument in %eax in the SMM save state
untouched that generally means the is no handler for GSMI.

Signed-off-by: Arthur Heymans <arthur@aheymans.xyz>
Signed-off-by: Patrick Rudolph <patrick.rudolph@9elements.com>
Link: https://lore.kernel.org/r/20191118101934.22526-4-patrick.rudolph@9elements.com
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
drivers/firmware/google/gsmi.c

index 974c769b75cfdd84db0943092a72e0e8f8bfe4a1..5b2011ebbe26dc5f6f63dad91211e604f3e9c298 100644 (file)
@@ -76,6 +76,7 @@
 #define GSMI_CMD_LOG_S0IX_RESUME       0x0b
 #define GSMI_CMD_CLEAR_CONFIG          0x20
 #define GSMI_CMD_HANDSHAKE_TYPE                0xC1
+#define GSMI_CMD_RESERVED              0xff
 
 /* Magic entry type for kernel events */
 #define GSMI_LOG_ENTRY_TYPE_KERNEL     0xDEAD
@@ -746,6 +747,7 @@ MODULE_DEVICE_TABLE(dmi, gsmi_dmi_table);
 static __init int gsmi_system_valid(void)
 {
        u32 hash;
+       u16 cmd, result;
 
        if (!dmi_check_system(gsmi_dmi_table))
                return -ENODEV;
@@ -780,6 +782,23 @@ static __init int gsmi_system_valid(void)
                return -ENODEV;
        }
 
+       /* Test the smihandler with a bogus command. If it leaves the
+        * calling argument in %ax untouched, there is no handler for
+        * GSMI commands.
+        */
+       cmd = GSMI_CALLBACK | GSMI_CMD_RESERVED << 8;
+       asm volatile (
+               "outb %%al, %%dx\n\t"
+               : "=a" (result)
+               : "0" (cmd),
+                 "d" (acpi_gbl_FADT.smi_command)
+               : "memory", "cc"
+               );
+       if (cmd == result) {
+               pr_info("gsmi: no gsmi handler in firmware\n");
+               return -ENODEV;
+       }
+
        /* Found */
        return 0;
 }