Skip to content

Commit

Permalink
platform/x86: hp-wmi: Changing bios_args.data to be dynamically alloc…
Browse files Browse the repository at this point in the history
…ated

The purpose of this patch is to remove 128 bytes buffer limitation
imposed in bios_args structure.

A limiting factor discovered during this investigation was the struct
bios_args.data size restriction.  The data member size limits all
possible WMI commands to those requiring buffer size of 128 bytes or
less. Several WMI commands and queries require a buffer size larger
than 128 bytes hence limiting current and feature supported by the
driver. It is for this reason, struct bios_args.data changed and is
dynamically allocated.  hp_wmi_perform_query function changed to
handle the memory allocation and release of any required buffer size.

All changes were validated on a HP ZBook Workstation notebook,
HP EliteBook x360, and HP EliteBook 850 G8.  Additional
validation was included in the test process to ensure no other
commands were incorrectly handled.

Signed-off-by: Jorge Lopez <[email protected]>
Link: https://lore.kernel.org/r/[email protected]
Reviewed-by: Hans de Goede <[email protected]>
Signed-off-by: Hans de Goede <[email protected]>
  • Loading branch information
Jorge Lopez authored and jwrdegoede committed Mar 15, 2022
1 parent be9d73e commit 4b4967c
Showing 1 changed file with 33 additions and 21 deletions.
54 changes: 33 additions & 21 deletions drivers/platform/x86/hp-wmi.c
Original file line number Diff line number Diff line change
Expand Up @@ -82,12 +82,17 @@ enum hp_wmi_event_ids {
HPWMI_BATTERY_CHARGE_PERIOD = 0x10,
};

/*
* struct bios_args buffer is dynamically allocated. New WMI command types
* were introduced that exceeds 128-byte data size. Changes to handle
* the data size allocation scheme were kept in hp_wmi_perform_qurey function.
*/
struct bios_args {
u32 signature;
u32 command;
u32 commandtype;
u32 datasize;
u8 data[128];
u8 data[];
};

enum hp_wmi_commandtype {
Expand Down Expand Up @@ -266,37 +271,43 @@ static inline int encode_outsize_for_pvsz(int outsize)
static int hp_wmi_perform_query(int query, enum hp_wmi_command command,
void *buffer, int insize, int outsize)
{
int mid;
struct acpi_buffer input, output = { ACPI_ALLOCATE_BUFFER, NULL };
struct bios_return *bios_return;
int actual_outsize;
union acpi_object *obj;
struct bios_args args = {
.signature = 0x55434553,
.command = command,
.commandtype = query,
.datasize = insize,
.data = { 0 },
};
struct acpi_buffer input = { sizeof(struct bios_args), &args };
struct acpi_buffer output = { ACPI_ALLOCATE_BUFFER, NULL };
int ret = 0;
union acpi_object *obj = NULL;
struct bios_args *args = NULL;
int mid, actual_outsize, ret;
size_t bios_args_size;

mid = encode_outsize_for_pvsz(outsize);
if (WARN_ON(mid < 0))
return mid;

if (WARN_ON(insize > sizeof(args.data)))
return -EINVAL;
memcpy(&args.data[0], buffer, insize);
bios_args_size = struct_size(args, data, insize);
args = kmalloc(bios_args_size, GFP_KERNEL);
if (!args)
return -ENOMEM;

wmi_evaluate_method(HPWMI_BIOS_GUID, 0, mid, &input, &output);
input.length = bios_args_size;
input.pointer = args;

obj = output.pointer;
args->signature = 0x55434553;
args->command = command;
args->commandtype = query;
args->datasize = insize;
memcpy(args->data, buffer, flex_array_size(args, data, insize));

if (!obj)
return -EINVAL;
ret = wmi_evaluate_method(HPWMI_BIOS_GUID, 0, mid, &input, &output);
if (ret)
goto out_free;

obj = output.pointer;
if (!obj) {
ret = -EINVAL;
goto out_free;
}

if (obj->type != ACPI_TYPE_BUFFER) {
pr_warn("query 0x%x returned an invalid object 0x%x\n", query, ret);
ret = -EINVAL;
goto out_free;
}
Expand All @@ -321,6 +332,7 @@ static int hp_wmi_perform_query(int query, enum hp_wmi_command command,

out_free:
kfree(obj);
kfree(args);
return ret;
}

Expand Down

0 comments on commit 4b4967c

Please sign in to comment.