Message ID | ff059ff32c00694450a38ce0b8b0c2ca9b9bdb24.1508515469.git.mario.limonciello@dell.com (mailing list archive) |
---|---|
State | Changes Requested, archived |
Delegated to: | Darren Hart |
Headers | show |
Hi Greg, Per our chat in Prague, I checked with Mario and there are no pending changes in the queue for this series. This, v11, is the one to review. On Fri, Oct 20, 2017 at 12:40:29PM -0500, Mario Limonciello wrote: > It's important for the driver to provide a R/W ioctl to ensure that > two competing userspace processes don't race to provide or read each > others data. > > This userspace character device will be used to perform SMBIOS calls > from any applications. > > It provides an ioctl that will allow passing the WMI calling > interface buffer between userspace and kernel space. > > This character device is intended to deprecate the dcdbas kernel module > and the interface that it provides to userspace. > > To perform an SMBIOS IOCTL call using the character device userspace will > perform a read() on the the character device. The WMI bus will provide > a u64 variable containing the necessary size of the IOCTL buffer. > > The API for interacting with this interface is defined in documentation > as well as the WMI uapi header provides the format of the structures. > > Not all userspace requests will be accepted. The dell-smbios filtering > functionality will be used to prevent access to certain tokens and calls. > > All whitelisted commands and tokens are now shared out to userspace so > applications don't need to define them in their own headers. > > Signed-off-by: Mario Limonciello <mario.limonciello@dell.com> > Reviewed-by: Edward O'Callaghan <quasisec@google.com> > --- > Documentation/ABI/testing/dell-smbios-wmi | 41 ++++++++++++++++++++++++ > drivers/platform/x86/dell-smbios-wmi.c | 53 ++++++++++++++++++++++++------- > drivers/platform/x86/dell-smbios.h | 32 ++----------------- > include/uapi/linux/wmi.h | 47 +++++++++++++++++++++++++++ > 4 files changed, 132 insertions(+), 41 deletions(-) > create mode 100644 Documentation/ABI/testing/dell-smbios-wmi > > diff --git a/Documentation/ABI/testing/dell-smbios-wmi b/Documentation/ABI/testing/dell-smbios-wmi > new file mode 100644 > index 000000000000..fc919ce16008 > --- /dev/null > +++ b/Documentation/ABI/testing/dell-smbios-wmi > @@ -0,0 +1,41 @@ > +What: /dev/wmi/dell-smbios > +Date: November 2017 > +KernelVersion: 4.15 > +Contact: "Mario Limonciello" <mario.limonciello@dell.com> > +Description: > + Perform SMBIOS calls on supported Dell machines. > + through the Dell ACPI-WMI interface. > + > + IOCTL's and buffer formats are defined in: > + <uapi/linux/wmi.h> > + > + 1) To perform an SMBIOS call from userspace, you'll need to > + first determine the minimum size of the calling interface > + buffer for your machine. > + Platforms that contain larger buffers can return larger > + objects from the system firmware. > + Commonly this size is either 4k or 32k. > + > + To determine the size of the buffer read() a u64 dword from > + the WMI character device /dev/wmi/dell-smbios. > + > + 2) After you've determined the minimum size of the calling > + interface buffer, you can allocate a structure that represents > + the structure documented above. > + > + 3) In the 'length' object store the size of the buffer you > + determined above and allocated. > + > + 4) In this buffer object, prepare as necessary for the SMBIOS > + call you're interested in. Typically SMBIOS buffers have > + "class", "select", and "input" defined to values that coincide > + with the data you are interested in. > + Documenting class/select/input values is outside of the scope > + of this documentation. Check with the libsmbios project for > + further documentation on these values. > + > + 6) Run the call by using ioctl() as described in the header. > + > + 7) The output will be returned in the buffer object. > + > + 8) Be sure to free up your allocated object. > diff --git a/drivers/platform/x86/dell-smbios-wmi.c b/drivers/platform/x86/dell-smbios-wmi.c > index d2b8438ea91f..04b0153c9bee 100644 > --- a/drivers/platform/x86/dell-smbios-wmi.c > +++ b/drivers/platform/x86/dell-smbios-wmi.c > @@ -30,17 +30,6 @@ struct misc_bios_flags_structure { > > #define DELL_WMI_SMBIOS_GUID "A80593CE-A997-11DA-B012-B622A1EF5492" > > -struct dell_wmi_extensions { > - __u32 argattrib; > - __u32 blength; > - __u8 data[]; > -} __packed; > - > -struct dell_wmi_smbios_buffer { > - struct calling_interface_buffer std; > - struct dell_wmi_extensions ext; > -} __packed; > - > struct wmi_smbios_priv { > struct dell_wmi_smbios_buffer *buf; > struct list_head list; > @@ -117,6 +106,41 @@ int dell_smbios_wmi_call(struct calling_interface_buffer *buffer) > return ret; > } > > +static long dell_smbios_wmi_filter(struct wmi_device *wdev, unsigned int cmd, > + struct wmi_ioctl_buffer *arg) > +{ > + struct wmi_smbios_priv *priv; > + int ret = 0; > + > + switch (cmd) { > + case DELL_WMI_SMBIOS_CMD: > + mutex_lock(&call_mutex); > + priv = dev_get_drvdata(&wdev->dev); > + if (!priv) { > + ret = -ENODEV; > + goto fail_smbios_cmd; > + } > + memcpy(priv->buf, arg, priv->req_buf_size); > + if (dell_smbios_call_filter(&wdev->dev, &priv->buf->std)) { > + dev_err(&wdev->dev, "Invalid call %d/%d:%8x\n", > + priv->buf->std.class, priv->buf->std.select, > + priv->buf->std.input[0]); > + ret = -EFAULT; > + goto fail_smbios_cmd; > + } > + ret = run_smbios_call(priv->wdev); > + if (ret) > + goto fail_smbios_cmd; > + memcpy(arg, priv->buf, priv->req_buf_size); > +fail_smbios_cmd: > + mutex_unlock(&call_mutex); > + break; > + default: > + ret = -ENOIOCTLCMD; > + } > + return ret; > +} > + > static int dell_smbios_wmi_probe(struct wmi_device *wdev) > { > struct wmi_smbios_priv *priv; > @@ -135,6 +159,12 @@ static int dell_smbios_wmi_probe(struct wmi_device *wdev) > if (!dell_wmi_get_size(&priv->req_buf_size)) > return -EPROBE_DEFER; > > + /* add in the length object we will use internally with ioctl */ > + priv->req_buf_size += sizeof(u64); > + ret = set_required_buffer_size(wdev, priv->req_buf_size); > + if (ret) > + return ret; > + > count = get_order(priv->req_buf_size); > priv->buf = (void *)__get_free_pages(GFP_KERNEL, count); > if (!priv->buf) > @@ -210,6 +240,7 @@ static struct wmi_driver dell_smbios_wmi_driver = { > .probe = dell_smbios_wmi_probe, > .remove = dell_smbios_wmi_remove, > .id_table = dell_smbios_wmi_id_table, > + .filter_callback = dell_smbios_wmi_filter, > }; > > static int __init init_dell_smbios_wmi(void) > diff --git a/drivers/platform/x86/dell-smbios.h b/drivers/platform/x86/dell-smbios.h > index 23256f79a4b8..138d478d9adc 100644 > --- a/drivers/platform/x86/dell-smbios.h > +++ b/drivers/platform/x86/dell-smbios.h > @@ -17,23 +17,11 @@ > #define _DELL_SMBIOS_H_ > > #include <linux/device.h> > +#include <uapi/linux/wmi.h> > > -/* Classes and selects used in kernel drivers */ > -#define CLASS_TOKEN_READ 0 > -#define CLASS_TOKEN_WRITE 1 > -#define SELECT_TOKEN_STD 0 > -#define SELECT_TOKEN_BAT 1 > -#define SELECT_TOKEN_AC 2 > +/* Classes and selects used only in kernel drivers */ > #define CLASS_KBD_BACKLIGHT 4 > #define SELECT_KBD_BACKLIGHT 11 > -#define CLASS_FLASH_INTERFACE 7 > -#define SELECT_FLASH_INTERFACE 3 > -#define CLASS_ADMIN_PROP 10 > -#define SELECT_ADMIN_PROP 3 > -#define CLASS_INFO 17 > -#define SELECT_RFKILL 11 > -#define SELECT_APP_REGISTRATION 3 > -#define SELECT_DOCK 22 > > /* Tokens used in kernel drivers, any of these > * should be filtered from userspace access > @@ -50,24 +38,8 @@ > #define GLOBAL_MIC_MUTE_ENABLE 0x0364 > #define GLOBAL_MIC_MUTE_DISABLE 0x0365 > > -/* tokens whitelisted to userspace use */ > -#define CAPSULE_EN_TOKEN 0x0461 > -#define CAPSULE_DIS_TOKEN 0x0462 > -#define WSMT_EN_TOKEN 0x04EC > -#define WSMT_DIS_TOKEN 0x04ED > - > struct notifier_block; > > -/* This structure will be modified by the firmware when we enter > - * system management mode, hence the volatiles */ > - > -struct calling_interface_buffer { > - u16 class; > - u16 select; > - volatile u32 input[4]; > - volatile u32 output[4]; > -} __packed; > - > struct calling_interface_token { > u16 tokenID; > u16 location; > diff --git a/include/uapi/linux/wmi.h b/include/uapi/linux/wmi.h > index 7e52350ac9b3..5ff61f2d37ba 100644 > --- a/include/uapi/linux/wmi.h > +++ b/include/uapi/linux/wmi.h > @@ -10,6 +10,7 @@ > #ifndef _UAPI_LINUX_WMI_H > #define _UAPI_LINUX_WMI_H > > +#include <linux/ioctl.h> > #include <linux/types.h> > > /* WMI bus will filter all WMI vendor driver requests through this IOC */ > @@ -23,4 +24,50 @@ struct wmi_ioctl_buffer { > __u8 data[]; > }; > > +/* This structure may be modified by the firmware when we enter > + * system management mode through SMM, hence the volatiles > + */ > +struct calling_interface_buffer { > + __u16 class; > + __u16 select; > + volatile __u32 input[4]; > + volatile __u32 output[4]; > +} __packed; > + > +struct dell_wmi_extensions { > + __u32 argattrib; > + __u32 blength; > + __u8 data[]; > +} __packed; > + > +struct dell_wmi_smbios_buffer { > + __u64 length; > + struct calling_interface_buffer std; > + struct dell_wmi_extensions ext; > +} __packed; > + > +/* Whitelisted smbios class/select commands */ > +#define CLASS_TOKEN_READ 0 > +#define CLASS_TOKEN_WRITE 1 > +#define SELECT_TOKEN_STD 0 > +#define SELECT_TOKEN_BAT 1 > +#define SELECT_TOKEN_AC 2 > +#define CLASS_FLASH_INTERFACE 7 > +#define SELECT_FLASH_INTERFACE 3 > +#define CLASS_ADMIN_PROP 10 > +#define SELECT_ADMIN_PROP 3 > +#define CLASS_INFO 17 > +#define SELECT_RFKILL 11 > +#define SELECT_APP_REGISTRATION 3 > +#define SELECT_DOCK 22 > + > +/* whitelisted tokens */ > +#define CAPSULE_EN_TOKEN 0x0461 > +#define CAPSULE_DIS_TOKEN 0x0462 > +#define WSMT_EN_TOKEN 0x04EC > +#define WSMT_DIS_TOKEN 0x04ED > + > +/* Dell SMBIOS calling IOCTL command used by dell-smbios-wmi */ > +#define DELL_WMI_SMBIOS_CMD _IOWR(WMI_IOC, 0, struct dell_wmi_smbios_buffer) > + > #endif > -- > 2.14.1 > >
On Sat, Oct 21, 2017 at 4:40 AM, Mario Limonciello <mario.limonciello@dell.com> wrote: > It's important for the driver to provide a R/W ioctl to ensure that > two competing userspace processes don't race to provide or read each > others data. > > This userspace character device will be used to perform SMBIOS calls > from any applications. > > It provides an ioctl that will allow passing the WMI calling > interface buffer between userspace and kernel space. > > This character device is intended to deprecate the dcdbas kernel module > and the interface that it provides to userspace. > > To perform an SMBIOS IOCTL call using the character device userspace will > perform a read() on the the character device. The WMI bus will provide > a u64 variable containing the necessary size of the IOCTL buffer. > > The API for interacting with this interface is defined in documentation > as well as the WMI uapi header provides the format of the structures. > > Not all userspace requests will be accepted. The dell-smbios filtering > functionality will be used to prevent access to certain tokens and calls. > > All whitelisted commands and tokens are now shared out to userspace so > applications don't need to define them in their own headers. > > Signed-off-by: Mario Limonciello <mario.limonciello@dell.com> > Reviewed-by: Edward O'Callaghan <quasisec@google.com> > --- > Documentation/ABI/testing/dell-smbios-wmi | 41 ++++++++++++++++++++++++ > drivers/platform/x86/dell-smbios-wmi.c | 53 ++++++++++++++++++++++++------- > drivers/platform/x86/dell-smbios.h | 32 ++----------------- > include/uapi/linux/wmi.h | 47 +++++++++++++++++++++++++++ > 4 files changed, 132 insertions(+), 41 deletions(-) > create mode 100644 Documentation/ABI/testing/dell-smbios-wmi > > diff --git a/Documentation/ABI/testing/dell-smbios-wmi b/Documentation/ABI/testing/dell-smbios-wmi > new file mode 100644 > index 000000000000..fc919ce16008 > --- /dev/null > +++ b/Documentation/ABI/testing/dell-smbios-wmi > @@ -0,0 +1,41 @@ > +What: /dev/wmi/dell-smbios > +Date: November 2017 > +KernelVersion: 4.15 > +Contact: "Mario Limonciello" <mario.limonciello@dell.com> > +Description: > + Perform SMBIOS calls on supported Dell machines. > + through the Dell ACPI-WMI interface. > + > + IOCTL's and buffer formats are defined in: > + <uapi/linux/wmi.h> > + > + 1) To perform an SMBIOS call from userspace, you'll need to > + first determine the minimum size of the calling interface > + buffer for your machine. > + Platforms that contain larger buffers can return larger > + objects from the system firmware. > + Commonly this size is either 4k or 32k. > + > + To determine the size of the buffer read() a u64 dword from > + the WMI character device /dev/wmi/dell-smbios. > + > + 2) After you've determined the minimum size of the calling > + interface buffer, you can allocate a structure that represents > + the structure documented above. > + > + 3) In the 'length' object store the size of the buffer you > + determined above and allocated. > + > + 4) In this buffer object, prepare as necessary for the SMBIOS > + call you're interested in. Typically SMBIOS buffers have > + "class", "select", and "input" defined to values that coincide > + with the data you are interested in. > + Documenting class/select/input values is outside of the scope > + of this documentation. Check with the libsmbios project for > + further documentation on these values. > + > + 6) Run the call by using ioctl() as described in the header. > + > + 7) The output will be returned in the buffer object. > + > + 8) Be sure to free up your allocated object. > diff --git a/drivers/platform/x86/dell-smbios-wmi.c b/drivers/platform/x86/dell-smbios-wmi.c > index d2b8438ea91f..04b0153c9bee 100644 > --- a/drivers/platform/x86/dell-smbios-wmi.c > +++ b/drivers/platform/x86/dell-smbios-wmi.c > @@ -30,17 +30,6 @@ struct misc_bios_flags_structure { > > #define DELL_WMI_SMBIOS_GUID "A80593CE-A997-11DA-B012-B622A1EF5492" > > -struct dell_wmi_extensions { > - __u32 argattrib; > - __u32 blength; > - __u8 data[]; > -} __packed; > - > -struct dell_wmi_smbios_buffer { > - struct calling_interface_buffer std; > - struct dell_wmi_extensions ext; > -} __packed; > - > struct wmi_smbios_priv { > struct dell_wmi_smbios_buffer *buf; > struct list_head list; > @@ -117,6 +106,41 @@ int dell_smbios_wmi_call(struct calling_interface_buffer *buffer) > return ret; > } > > +static long dell_smbios_wmi_filter(struct wmi_device *wdev, unsigned int cmd, > + struct wmi_ioctl_buffer *arg) > +{ > + struct wmi_smbios_priv *priv; > + int ret = 0; > + > + switch (cmd) { > + case DELL_WMI_SMBIOS_CMD: > + mutex_lock(&call_mutex); > + priv = dev_get_drvdata(&wdev->dev); > + if (!priv) { > + ret = -ENODEV; > + goto fail_smbios_cmd; > + } > + memcpy(priv->buf, arg, priv->req_buf_size); > + if (dell_smbios_call_filter(&wdev->dev, &priv->buf->std)) { > + dev_err(&wdev->dev, "Invalid call %d/%d:%8x\n", > + priv->buf->std.class, priv->buf->std.select, > + priv->buf->std.input[0]); > + ret = -EFAULT; > + goto fail_smbios_cmd; > + } > + ret = run_smbios_call(priv->wdev); > + if (ret) > + goto fail_smbios_cmd; > + memcpy(arg, priv->buf, priv->req_buf_size); > +fail_smbios_cmd: > + mutex_unlock(&call_mutex); > + break; > + default: > + ret = -ENOIOCTLCMD; > + } > + return ret; > +} > + > static int dell_smbios_wmi_probe(struct wmi_device *wdev) > { > struct wmi_smbios_priv *priv; > @@ -135,6 +159,12 @@ static int dell_smbios_wmi_probe(struct wmi_device *wdev) > if (!dell_wmi_get_size(&priv->req_buf_size)) > return -EPROBE_DEFER; > > + /* add in the length object we will use internally with ioctl */ > + priv->req_buf_size += sizeof(u64); > + ret = set_required_buffer_size(wdev, priv->req_buf_size); > + if (ret) > + return ret; > + > count = get_order(priv->req_buf_size); > priv->buf = (void *)__get_free_pages(GFP_KERNEL, count); > if (!priv->buf) > @@ -210,6 +240,7 @@ static struct wmi_driver dell_smbios_wmi_driver = { > .probe = dell_smbios_wmi_probe, > .remove = dell_smbios_wmi_remove, > .id_table = dell_smbios_wmi_id_table, > + .filter_callback = dell_smbios_wmi_filter, > }; > > static int __init init_dell_smbios_wmi(void) > diff --git a/drivers/platform/x86/dell-smbios.h b/drivers/platform/x86/dell-smbios.h > index 23256f79a4b8..138d478d9adc 100644 > --- a/drivers/platform/x86/dell-smbios.h > +++ b/drivers/platform/x86/dell-smbios.h > @@ -17,23 +17,11 @@ > #define _DELL_SMBIOS_H_ > > #include <linux/device.h> > +#include <uapi/linux/wmi.h> > > -/* Classes and selects used in kernel drivers */ > -#define CLASS_TOKEN_READ 0 > -#define CLASS_TOKEN_WRITE 1 > -#define SELECT_TOKEN_STD 0 > -#define SELECT_TOKEN_BAT 1 > -#define SELECT_TOKEN_AC 2 > +/* Classes and selects used only in kernel drivers */ > #define CLASS_KBD_BACKLIGHT 4 > #define SELECT_KBD_BACKLIGHT 11 > -#define CLASS_FLASH_INTERFACE 7 > -#define SELECT_FLASH_INTERFACE 3 > -#define CLASS_ADMIN_PROP 10 > -#define SELECT_ADMIN_PROP 3 > -#define CLASS_INFO 17 > -#define SELECT_RFKILL 11 > -#define SELECT_APP_REGISTRATION 3 > -#define SELECT_DOCK 22 > > /* Tokens used in kernel drivers, any of these > * should be filtered from userspace access > @@ -50,24 +38,8 @@ > #define GLOBAL_MIC_MUTE_ENABLE 0x0364 > #define GLOBAL_MIC_MUTE_DISABLE 0x0365 > > -/* tokens whitelisted to userspace use */ > -#define CAPSULE_EN_TOKEN 0x0461 > -#define CAPSULE_DIS_TOKEN 0x0462 > -#define WSMT_EN_TOKEN 0x04EC > -#define WSMT_DIS_TOKEN 0x04ED > - > struct notifier_block; > > -/* This structure will be modified by the firmware when we enter > - * system management mode, hence the volatiles */ > - > -struct calling_interface_buffer { > - u16 class; > - u16 select; > - volatile u32 input[4]; > - volatile u32 output[4]; > -} __packed; > - > struct calling_interface_token { > u16 tokenID; > u16 location; > diff --git a/include/uapi/linux/wmi.h b/include/uapi/linux/wmi.h > index 7e52350ac9b3..5ff61f2d37ba 100644 > --- a/include/uapi/linux/wmi.h > +++ b/include/uapi/linux/wmi.h > @@ -10,6 +10,7 @@ > #ifndef _UAPI_LINUX_WMI_H > #define _UAPI_LINUX_WMI_H > > +#include <linux/ioctl.h> > #include <linux/types.h> > > /* WMI bus will filter all WMI vendor driver requests through this IOC */ > @@ -23,4 +24,50 @@ struct wmi_ioctl_buffer { > __u8 data[]; > }; > > +/* This structure may be modified by the firmware when we enter > + * system management mode through SMM, hence the volatiles > + */ > +struct calling_interface_buffer { > + __u16 class; Hey Mario, I just realized that there is a slight problem calling this identifier "class" for userspace that happens to be written in C++ that #includes this header as class is a reversed word. Perhaps we could rename it to class_ or something otherwise userspace has to shim with a C object and extern it with new identifiers to the C++ component, which is awkward. Kind Regards, Edward. > + __u16 select; > + volatile __u32 input[4]; > + volatile __u32 output[4]; > +} __packed; > + > +struct dell_wmi_extensions { > + __u32 argattrib; > + __u32 blength; > + __u8 data[]; > +} __packed; > + > +struct dell_wmi_smbios_buffer { > + __u64 length; > + struct calling_interface_buffer std; > + struct dell_wmi_extensions ext; > +} __packed; > + > +/* Whitelisted smbios class/select commands */ > +#define CLASS_TOKEN_READ 0 > +#define CLASS_TOKEN_WRITE 1 > +#define SELECT_TOKEN_STD 0 > +#define SELECT_TOKEN_BAT 1 > +#define SELECT_TOKEN_AC 2 > +#define CLASS_FLASH_INTERFACE 7 > +#define SELECT_FLASH_INTERFACE 3 > +#define CLASS_ADMIN_PROP 10 > +#define SELECT_ADMIN_PROP 3 > +#define CLASS_INFO 17 > +#define SELECT_RFKILL 11 > +#define SELECT_APP_REGISTRATION 3 > +#define SELECT_DOCK 22 > + > +/* whitelisted tokens */ > +#define CAPSULE_EN_TOKEN 0x0461 > +#define CAPSULE_DIS_TOKEN 0x0462 > +#define WSMT_EN_TOKEN 0x04EC > +#define WSMT_DIS_TOKEN 0x04ED > + > +/* Dell SMBIOS calling IOCTL command used by dell-smbios-wmi */ > +#define DELL_WMI_SMBIOS_CMD _IOWR(WMI_IOC, 0, struct dell_wmi_smbios_buffer) > + > #endif > -- > 2.14.1 >
> > +/* This structure may be modified by the firmware when we enter > > + * system management mode through SMM, hence the volatiles > > + */ > > +struct calling_interface_buffer { > > + __u16 class; > > Hey Mario, > > I just realized that there is a slight problem calling this identifier > "class" for userspace that happens to be written in C++ that #includes > this header as class is a reversed word. > Perhaps we could rename it to class_ or something otherwise userspace > has to shim with a C object and extern it with new identifiers to the > C++ component, which is awkward. Edward, Ah darn, I wish we would have caught this earlier in the series development, but it's better to do fix it now rather than after the uapi has been included in a kernel. Darren, I think I should adjust the series for this change to s/class/cmd_class; s/select/cmd_select/ . As ->class is used in many patches in the series, it will require be better to resend as v12 rather than a single patch that changes this one thing. I'll send it later this afternoon. Thanks,
diff --git a/Documentation/ABI/testing/dell-smbios-wmi b/Documentation/ABI/testing/dell-smbios-wmi new file mode 100644 index 000000000000..fc919ce16008 --- /dev/null +++ b/Documentation/ABI/testing/dell-smbios-wmi @@ -0,0 +1,41 @@ +What: /dev/wmi/dell-smbios +Date: November 2017 +KernelVersion: 4.15 +Contact: "Mario Limonciello" <mario.limonciello@dell.com> +Description: + Perform SMBIOS calls on supported Dell machines. + through the Dell ACPI-WMI interface. + + IOCTL's and buffer formats are defined in: + <uapi/linux/wmi.h> + + 1) To perform an SMBIOS call from userspace, you'll need to + first determine the minimum size of the calling interface + buffer for your machine. + Platforms that contain larger buffers can return larger + objects from the system firmware. + Commonly this size is either 4k or 32k. + + To determine the size of the buffer read() a u64 dword from + the WMI character device /dev/wmi/dell-smbios. + + 2) After you've determined the minimum size of the calling + interface buffer, you can allocate a structure that represents + the structure documented above. + + 3) In the 'length' object store the size of the buffer you + determined above and allocated. + + 4) In this buffer object, prepare as necessary for the SMBIOS + call you're interested in. Typically SMBIOS buffers have + "class", "select", and "input" defined to values that coincide + with the data you are interested in. + Documenting class/select/input values is outside of the scope + of this documentation. Check with the libsmbios project for + further documentation on these values. + + 6) Run the call by using ioctl() as described in the header. + + 7) The output will be returned in the buffer object. + + 8) Be sure to free up your allocated object. diff --git a/drivers/platform/x86/dell-smbios-wmi.c b/drivers/platform/x86/dell-smbios-wmi.c index d2b8438ea91f..04b0153c9bee 100644 --- a/drivers/platform/x86/dell-smbios-wmi.c +++ b/drivers/platform/x86/dell-smbios-wmi.c @@ -30,17 +30,6 @@ struct misc_bios_flags_structure { #define DELL_WMI_SMBIOS_GUID "A80593CE-A997-11DA-B012-B622A1EF5492" -struct dell_wmi_extensions { - __u32 argattrib; - __u32 blength; - __u8 data[]; -} __packed; - -struct dell_wmi_smbios_buffer { - struct calling_interface_buffer std; - struct dell_wmi_extensions ext; -} __packed; - struct wmi_smbios_priv { struct dell_wmi_smbios_buffer *buf; struct list_head list; @@ -117,6 +106,41 @@ int dell_smbios_wmi_call(struct calling_interface_buffer *buffer) return ret; } +static long dell_smbios_wmi_filter(struct wmi_device *wdev, unsigned int cmd, + struct wmi_ioctl_buffer *arg) +{ + struct wmi_smbios_priv *priv; + int ret = 0; + + switch (cmd) { + case DELL_WMI_SMBIOS_CMD: + mutex_lock(&call_mutex); + priv = dev_get_drvdata(&wdev->dev); + if (!priv) { + ret = -ENODEV; + goto fail_smbios_cmd; + } + memcpy(priv->buf, arg, priv->req_buf_size); + if (dell_smbios_call_filter(&wdev->dev, &priv->buf->std)) { + dev_err(&wdev->dev, "Invalid call %d/%d:%8x\n", + priv->buf->std.class, priv->buf->std.select, + priv->buf->std.input[0]); + ret = -EFAULT; + goto fail_smbios_cmd; + } + ret = run_smbios_call(priv->wdev); + if (ret) + goto fail_smbios_cmd; + memcpy(arg, priv->buf, priv->req_buf_size); +fail_smbios_cmd: + mutex_unlock(&call_mutex); + break; + default: + ret = -ENOIOCTLCMD; + } + return ret; +} + static int dell_smbios_wmi_probe(struct wmi_device *wdev) { struct wmi_smbios_priv *priv; @@ -135,6 +159,12 @@ static int dell_smbios_wmi_probe(struct wmi_device *wdev) if (!dell_wmi_get_size(&priv->req_buf_size)) return -EPROBE_DEFER; + /* add in the length object we will use internally with ioctl */ + priv->req_buf_size += sizeof(u64); + ret = set_required_buffer_size(wdev, priv->req_buf_size); + if (ret) + return ret; + count = get_order(priv->req_buf_size); priv->buf = (void *)__get_free_pages(GFP_KERNEL, count); if (!priv->buf) @@ -210,6 +240,7 @@ static struct wmi_driver dell_smbios_wmi_driver = { .probe = dell_smbios_wmi_probe, .remove = dell_smbios_wmi_remove, .id_table = dell_smbios_wmi_id_table, + .filter_callback = dell_smbios_wmi_filter, }; static int __init init_dell_smbios_wmi(void) diff --git a/drivers/platform/x86/dell-smbios.h b/drivers/platform/x86/dell-smbios.h index 23256f79a4b8..138d478d9adc 100644 --- a/drivers/platform/x86/dell-smbios.h +++ b/drivers/platform/x86/dell-smbios.h @@ -17,23 +17,11 @@ #define _DELL_SMBIOS_H_ #include <linux/device.h> +#include <uapi/linux/wmi.h> -/* Classes and selects used in kernel drivers */ -#define CLASS_TOKEN_READ 0 -#define CLASS_TOKEN_WRITE 1 -#define SELECT_TOKEN_STD 0 -#define SELECT_TOKEN_BAT 1 -#define SELECT_TOKEN_AC 2 +/* Classes and selects used only in kernel drivers */ #define CLASS_KBD_BACKLIGHT 4 #define SELECT_KBD_BACKLIGHT 11 -#define CLASS_FLASH_INTERFACE 7 -#define SELECT_FLASH_INTERFACE 3 -#define CLASS_ADMIN_PROP 10 -#define SELECT_ADMIN_PROP 3 -#define CLASS_INFO 17 -#define SELECT_RFKILL 11 -#define SELECT_APP_REGISTRATION 3 -#define SELECT_DOCK 22 /* Tokens used in kernel drivers, any of these * should be filtered from userspace access @@ -50,24 +38,8 @@ #define GLOBAL_MIC_MUTE_ENABLE 0x0364 #define GLOBAL_MIC_MUTE_DISABLE 0x0365 -/* tokens whitelisted to userspace use */ -#define CAPSULE_EN_TOKEN 0x0461 -#define CAPSULE_DIS_TOKEN 0x0462 -#define WSMT_EN_TOKEN 0x04EC -#define WSMT_DIS_TOKEN 0x04ED - struct notifier_block; -/* This structure will be modified by the firmware when we enter - * system management mode, hence the volatiles */ - -struct calling_interface_buffer { - u16 class; - u16 select; - volatile u32 input[4]; - volatile u32 output[4]; -} __packed; - struct calling_interface_token { u16 tokenID; u16 location; diff --git a/include/uapi/linux/wmi.h b/include/uapi/linux/wmi.h index 7e52350ac9b3..5ff61f2d37ba 100644 --- a/include/uapi/linux/wmi.h +++ b/include/uapi/linux/wmi.h @@ -10,6 +10,7 @@ #ifndef _UAPI_LINUX_WMI_H #define _UAPI_LINUX_WMI_H +#include <linux/ioctl.h> #include <linux/types.h> /* WMI bus will filter all WMI vendor driver requests through this IOC */ @@ -23,4 +24,50 @@ struct wmi_ioctl_buffer { __u8 data[]; }; +/* This structure may be modified by the firmware when we enter + * system management mode through SMM, hence the volatiles + */ +struct calling_interface_buffer { + __u16 class; + __u16 select; + volatile __u32 input[4]; + volatile __u32 output[4]; +} __packed; + +struct dell_wmi_extensions { + __u32 argattrib; + __u32 blength; + __u8 data[]; +} __packed; + +struct dell_wmi_smbios_buffer { + __u64 length; + struct calling_interface_buffer std; + struct dell_wmi_extensions ext; +} __packed; + +/* Whitelisted smbios class/select commands */ +#define CLASS_TOKEN_READ 0 +#define CLASS_TOKEN_WRITE 1 +#define SELECT_TOKEN_STD 0 +#define SELECT_TOKEN_BAT 1 +#define SELECT_TOKEN_AC 2 +#define CLASS_FLASH_INTERFACE 7 +#define SELECT_FLASH_INTERFACE 3 +#define CLASS_ADMIN_PROP 10 +#define SELECT_ADMIN_PROP 3 +#define CLASS_INFO 17 +#define SELECT_RFKILL 11 +#define SELECT_APP_REGISTRATION 3 +#define SELECT_DOCK 22 + +/* whitelisted tokens */ +#define CAPSULE_EN_TOKEN 0x0461 +#define CAPSULE_DIS_TOKEN 0x0462 +#define WSMT_EN_TOKEN 0x04EC +#define WSMT_DIS_TOKEN 0x04ED + +/* Dell SMBIOS calling IOCTL command used by dell-smbios-wmi */ +#define DELL_WMI_SMBIOS_CMD _IOWR(WMI_IOC, 0, struct dell_wmi_smbios_buffer) + #endif