From: Matt Fleming <matt-mF/unelCI9GS6iBeEJttW/XRex20P6io@public.gmane.org>
To: Lukas Wunner <lukas-JFq808J9C/izQB+pC5nmwQ@public.gmane.org>
Cc: linux-efi-u79uwXL29TY76Z2rM5mHXA@public.gmane.org,
Andreas Noever
<andreas.noever-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>,
Peter Jones <pjones-H+wXaHxf7aLQT0dZR+AlfA@public.gmane.org>,
Ard Biesheuvel
<ard.biesheuvel-QSEj5FYQhm4dnm+yROfE0A@public.gmane.org>
Subject: Re: [PATCH v3 2/3] x86/efi: Retrieve and assign Apple device properties
Date: Thu, 3 Nov 2016 23:31:00 +0000 [thread overview]
Message-ID: <20161103233100.GC8845@codeblueprint.co.uk> (raw)
In-Reply-To: <495c463bcb78131bf04ece648719fc8b3e9bd4ba.1478145888.git.lukas-JFq808J9C/izQB+pC5nmwQ@public.gmane.org>
Looks OK, just some minor comments below.
On Thu, 03 Nov, at 11:18:48AM, Lukas Wunner wrote:
> diff --git a/arch/x86/boot/compressed/eboot.c b/arch/x86/boot/compressed/eboot.c
> index cc69e37..ff01637 100644
> --- a/arch/x86/boot/compressed/eboot.c
> +++ b/arch/x86/boot/compressed/eboot.c
> @@ -537,6 +537,63 @@ static void setup_efi_pci(struct boot_params *params)
> efi_call_early(free_pool, pci_handle);
> }
>
> +static void retrieve_apple_device_properties(struct boot_params *params)
> +{
> + efi_guid_t guid = APPLE_PROPERTIES_PROTOCOL_GUID;
> + struct setup_data *data, *new;
> + efi_status_t status;
> + void *properties;
> + u32 size = 0;
> +
> + status = efi_call_early(locate_protocol, &guid, NULL, &properties);
> + if (status != EFI_SUCCESS)
> + return;
> +
> + if ((efi_is_64bit() ?
> + ((apple_properties_protocol_64 *)properties)->version :
> + ((apple_properties_protocol_32 *)properties)->version)
> + != 0x10000) {
> + efi_printk(sys_table, "Unsupported properties proto version\n");
> + return;
> + }
It's a minor point, but please don't write the 32/64 code like this.
Either use two separate functions, like __file_size32() and
__file_size64(), or if that's two much code duplication stash the
version field and get_all pointer in stack-local variables at the
start of the function.
> + efi_early->call(efi_is_64bit() ?
> + ((apple_properties_protocol_64 *)properties)->get_all :
> + ((apple_properties_protocol_32 *)properties)->get_all,
> + properties, NULL, &size);
> + if (!size)
> + return;
> +
> + do {
> + status = efi_call_early(allocate_pool, EFI_LOADER_DATA,
> + size + sizeof(struct setup_data), &new);
> + if (status != EFI_SUCCESS) {
> + efi_printk(sys_table,
> + "Failed to alloc mem for properties\n");
> + return;
> + }
Newline here please.
> + status = efi_early->call(efi_is_64bit() ?
> + ((apple_properties_protocol_64 *)properties)->get_all :
> + ((apple_properties_protocol_32 *)properties)->get_all,
> + properties, new->data, &size);
And a newline here.
> + if (status == EFI_BUFFER_TOO_SMALL)
> + efi_call_early(free_pool, new);
> + } while (status == EFI_BUFFER_TOO_SMALL);
> +
> + new->type = SETUP_APPLE_PROPERTIES;
> + new->len = size;
> + new->next = 0;
> +
> + data = (struct setup_data *)(unsigned long)params->hdr.setup_data;
> + if (!data)
> + params->hdr.setup_data = (unsigned long)new;
> + else {
> + while (data->next)
> + data = (struct setup_data *)(unsigned long)data->next;
> + data->next = (unsigned long)new;
> + }
> +}
> +
> static efi_status_t
> setup_uga32(void **uga_handle, unsigned long size, u32 *width, u32 *height)
> {
> @@ -1068,6 +1125,7 @@ static efi_status_t exit_boot(struct boot_params *boot_params,
> struct boot_params *efi_main(struct efi_config *c,
> struct boot_params *boot_params)
> {
> + efi_char16_t const apple[] = { 'A', 'p', 'p', 'l', 'e', 0 };
> struct desc_ptr *gdt = NULL;
> efi_loaded_image_t *image;
> struct setup_header *hdr = &boot_params->hdr;
> @@ -1098,6 +1156,11 @@ struct boot_params *efi_main(struct efi_config *c,
>
> setup_efi_pci(boot_params);
>
> + if (!memcmp((void *)sys_table->fw_vendor, apple, sizeof(apple))) {
> + if (IS_ENABLED(CONFIG_APPLE_PROPERTIES))
> + retrieve_apple_device_properties(boot_params);
> + }
> +
> status = efi_call_early(allocate_pool, EFI_LOADER_DATA,
> sizeof(*gdt), (void **)&gdt);
> if (status != EFI_SUCCESS) {
Could you split this off into a setup_apple_properties() function to
mirror setup_efi_pci()?
> diff --git a/arch/x86/include/uapi/asm/bootparam.h b/arch/x86/include/uapi/asm/bootparam.h
> index c18ce67..b10bf31 100644
> --- a/arch/x86/include/uapi/asm/bootparam.h
> +++ b/arch/x86/include/uapi/asm/bootparam.h
> @@ -7,6 +7,7 @@
> #define SETUP_DTB 2
> #define SETUP_PCI 3
> #define SETUP_EFI 4
> +#define SETUP_APPLE_PROPERTIES 5
>
> /* ram_size flags */
> #define RAMDISK_IMAGE_START_MASK 0x07FF
> diff --git a/drivers/firmware/efi/Kconfig b/drivers/firmware/efi/Kconfig
> index 893fda4..2e78b0b 100644
> --- a/drivers/firmware/efi/Kconfig
> +++ b/drivers/firmware/efi/Kconfig
> @@ -129,6 +129,19 @@ config EFI_TEST
> Say Y here to enable the runtime services support via /dev/efi_test.
> If unsure, say N.
>
> +config APPLE_PROPERTIES
> + bool "Apple Device Properties"
> + depends on EFI_STUB && X86
> + select EFI_DEV_PATH_PARSER
> + select UCS2_STRING
> + help
> + Retrieve properties from EFI on Apple Macs and assign them to
> + devices, allowing for improved support of Apple hardware.
> + Properties that would otherwise be missing include the
> + Thunderbolt Device ROM and GPU configuration data.
> +
> + If unsure, say Y if you have a Mac. Otherwise N.
> +
> endmenu
>
> config UEFI_CPER
> diff --git a/drivers/firmware/efi/Makefile b/drivers/firmware/efi/Makefile
> index 3e91ae3..ad67342 100644
> --- a/drivers/firmware/efi/Makefile
> +++ b/drivers/firmware/efi/Makefile
> @@ -22,6 +22,7 @@ obj-$(CONFIG_EFI_FAKE_MEMMAP) += fake_mem.o
> obj-$(CONFIG_EFI_BOOTLOADER_CONTROL) += efibc.o
> obj-$(CONFIG_EFI_TEST) += test/
> obj-$(CONFIG_EFI_DEV_PATH_PARSER) += dev-path-parser.o
> +obj-$(CONFIG_APPLE_PROPERTIES) += apple-properties.o
>
> arm-obj-$(CONFIG_EFI) := arm-init.o arm-runtime.o
> obj-$(CONFIG_ARM) += $(arm-obj-y)
> diff --git a/drivers/firmware/efi/apple-properties.c b/drivers/firmware/efi/apple-properties.c
> new file mode 100644
> index 0000000..3b4d6a2
> --- /dev/null
> +++ b/drivers/firmware/efi/apple-properties.c
> @@ -0,0 +1,239 @@
> +/*
> + * apple-properties.c - EFI device properties on Macs
> + * Copyright (C) 2016 Lukas Wunner <lukas-JFq808J9C/izQB+pC5nmwQ@public.gmane.org>
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License (version 2) as
> + * published by the Free Software Foundation.
> + *
> + * This program is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
> + * GNU General Public License for more details.
> + *
> + * You should have received a copy of the GNU General Public License
> + * along with this program; if not, see <http://www.gnu.org/licenses/>.
> + */
> +
> +#define pr_fmt(fmt) "apple-properties: " fmt
> +
> +#include <linux/bootmem.h>
> +#include <linux/dmi.h>
> +#include <linux/efi.h>
> +#include <linux/property.h>
> +#include <linux/slab.h>
> +#include <linux/ucs2_string.h>
> +#include <asm/setup.h>
> +
> +static bool dump_properties __initdata;
> +
> +static int __init dump_properties_enable(char *arg)
> +{
> + dump_properties = true;
> + return 0;
> +}
> +
> +__setup("dump_apple_properties", dump_properties_enable);
> +
> +struct dev_header {
> + u32 len;
> + u32 prop_count;
> + struct efi_dev_path path[0];
> + /*
> + * followed by key/value pairs, each key and value preceded by u32 len,
> + * len includes itself, value may be empty (in which case its len is 4)
> + */
> +};
> +
> +struct properties_header {
> + u32 len;
> + u32 version;
> + u32 dev_count;
> + struct dev_header dev_header[0];
> +};
> +
> +static u8 one __initdata = 1;
> +
> +static void __init unmarshal_key_value_pairs(struct dev_header *dev_header,
> + struct device *dev, void *ptr,
> + struct property_entry entry[])
> +{
> + int i;
> +
> + for (i = 0; i < dev_header->prop_count; i++) {
> + int remaining = dev_header->len - (ptr - (void *)dev_header);
> + u32 key_len, val_len;
> + char *key;
> +
> + if (sizeof(key_len) > remaining)
> + break;
> + key_len = *(typeof(key_len) *)ptr;
> + if (key_len + sizeof(val_len) > remaining ||
> + key_len < sizeof(key_len) + sizeof(efi_char16_t) ||
> + *(efi_char16_t *)(ptr + sizeof(key_len)) == 0) {
> + dev_err(dev, "invalid property name len at %#zx\n",
> + ptr - (void *)dev_header);
> + break;
> + }
> + val_len = *(typeof(val_len) *)(ptr + key_len);
> + if (key_len + val_len > remaining ||
> + val_len < sizeof(val_len)) {
> + dev_err(dev, "invalid property val len at %#zx\n",
> + ptr - (void *)dev_header + key_len);
> + break;
> + }
Please sprinkle a few newlines to make this more readable.
> +
> + key = kzalloc((key_len - sizeof(key_len)) * 4 + 1, GFP_KERNEL);
> + if (!key) {
> + dev_err(dev, "cannot allocate property name\n");
> + break;
> + }
Could you add a comment to document the kzalloc() size argument above?
> + ucs2_as_utf8(key, ptr + sizeof(key_len),
> + key_len - sizeof(key_len));
> +
> + entry[i].name = key;
> + entry[i].is_array = true;
> + entry[i].length = val_len - sizeof(val_len);
> + entry[i].pointer.raw_data = ptr + key_len + sizeof(val_len);
> + if (!entry[i].length) {
> + /* driver core doesn't accept empty properties */
> + entry[i].length = 1;
> + entry[i].pointer.raw_data = &one;
> + }
> +
> + if (dump_properties) {
> + dev_info(dev, "property: %s\n", entry[i].name);
> + print_hex_dump(KERN_INFO, pr_fmt(), DUMP_PREFIX_OFFSET,
> + 16, 1, entry[i].pointer.raw_data,
> + entry[i].length, true);
> + }
> +
> + ptr += key_len + val_len;
> + }
> +
> + if (i != dev_header->prop_count) {
> + dev_err(dev, "got %d device properties, expected %u\n", i,
> + dev_header->prop_count);
> + print_hex_dump(KERN_ERR, pr_fmt(), DUMP_PREFIX_OFFSET,
> + 16, 1, dev_header, dev_header->len, true);
> + } else
> + dev_info(dev, "assigning %d device properties\n", i);
Mismatched braces are frowned upon in the CodingStyle guide. Please
use braces for both the 'if' and 'else'. Alternatively, return early
for one of the conditions (and save a level of indentation too).
> +}
> +
> +static int __init unmarshal_devices(struct properties_header *properties)
> +{
> + size_t offset = offsetof(struct properties_header, dev_header[0]);
> +
> + while (offset + sizeof(struct dev_header) < properties->len) {
> + struct dev_header *dev_header = (void *)properties + offset;
> + struct property_entry *entry = NULL;
> + struct device *dev;
> + size_t len;
> + int ret, i;
> + void *ptr;
> +
> + if (offset + dev_header->len > properties->len ||
> + dev_header->len <= sizeof(*dev_header)) {
> + pr_err("invalid len in dev_header at %#zx\n", offset);
> + return -EINVAL;
> + }
> +
> + ptr = dev_header->path;
> + len = dev_header->len - sizeof(*dev_header);
Newline please.
> + dev = efi_get_device_by_path((struct efi_dev_path **)&ptr, &len);
> + if (IS_ERR(dev)) {
> + pr_err("device path parse error %ld at %#zx:\n",
> + PTR_ERR(dev), ptr - (void *)dev_header);
> + print_hex_dump(KERN_ERR, pr_fmt(), DUMP_PREFIX_OFFSET,
> + 16, 1, dev_header, dev_header->len, true);
> + dev = NULL;
> + goto skip_device;
> + }
> +
> + entry = kcalloc(dev_header->prop_count + 1, sizeof(*entry),
> + GFP_KERNEL);
> + if (!entry) {
> + dev_err(dev, "cannot allocate properties\n");
> + goto skip_device;
> + }
> +
> + unmarshal_key_value_pairs(dev_header, dev, ptr, entry);
> + if (!entry[0].name)
> + goto skip_device;
> +
> + ret = device_add_properties(dev, entry); /* makes deep copy */
> + if (ret)
> + dev_err(dev, "error %d assigning properties\n", ret);
Newline.
> + for (i = 0; entry[i].name; i++)
> + kfree(entry[i].name);
> +
> +skip_device:
> + kfree(entry);
> + put_device(dev);
> + offset += dev_header->len;
> + }
> +
> + return 0;
> +}
> +
> +static int __init map_properties(void)
> +{
> + struct properties_header *properties;
> + struct setup_data *data;
> + u32 data_len;
> + u64 pa_data;
> + int ret;
> +
> + if (!dmi_match(DMI_SYS_VENDOR, "Apple Inc.") &&
> + !dmi_match(DMI_SYS_VENDOR, "Apple Computer, Inc."))
> + return 0;
> +
> + pa_data = boot_params.hdr.setup_data;
> + while (pa_data) {
> + data = ioremap(pa_data, sizeof(*data));
> + if (!data) {
> + pr_err("cannot map setup_data header\n");
> + return -ENOMEM;
> + }
> +
> + if (data->type != SETUP_APPLE_PROPERTIES) {
> + pa_data = data->next;
> + iounmap(data);
> + continue;
> + }
> +
> + data_len = data->len;
> + iounmap(data);
Newline.
> + data = ioremap(pa_data, sizeof(*data) + data_len);
> + if (!data) {
> + pr_err("cannot map setup_data payload\n");
> + return -ENOMEM;
> + }
> +
> + properties = (struct properties_header *)data->data;
> + if (properties->version != 1) {
> + pr_err("unsupported version:\n");
> + print_hex_dump(KERN_ERR, pr_fmt(), DUMP_PREFIX_OFFSET,
> + 16, 1, properties, data_len, true);
> + ret = -ENOTSUPP;
> + } else if (properties->len != data_len) {
> + pr_err("length mismatch, expected %u\n", data_len);
> + print_hex_dump(KERN_ERR, pr_fmt(), DUMP_PREFIX_OFFSET,
> + 16, 1, properties, data_len, true);
> + ret = -EINVAL;
> + } else
> + ret = unmarshal_devices(properties);
> +
> + /*
> + * can only free the setup_data payload but not its header
> + * to avoid breaking the chain of ->next pointers
> + */
Multi-line comments should begin with capital letters and end with
full-stops.
> + data->len = 0;
> + iounmap(data);
> + free_bootmem_late(pa_data + sizeof(*data), data_len);
Newline.
> + return ret;
> + }
> + return 0;
> +}
> +
> +fs_initcall(map_properties);
> diff --git a/include/linux/efi.h b/include/linux/efi.h
> index 2617672..88f343f 100644
> --- a/include/linux/efi.h
> +++ b/include/linux/efi.h
> @@ -443,6 +443,22 @@ typedef struct {
> #define EFI_PCI_IO_ATTRIBUTE_VGA_PALETTE_IO_16 0x20000
> #define EFI_PCI_IO_ATTRIBUTE_VGA_IO_16 0x40000
>
> +typedef struct {
> + u32 version;
> + u32 get;
> + u32 set;
> + u32 del;
> + u32 get_all;
> +} apple_properties_protocol_32;
> +
> +typedef struct {
> + u64 version;
> + u64 get;
> + u64 set;
> + u64 del;
> + u64 get_all;
> +} apple_properties_protocol_64;
> +
Please append a '_t' to both of these so it's obvious they're types.
> /*
> * Types and defines for EFI ResetSystem
> */
> @@ -592,6 +608,7 @@ void efi_native_runtime_setup(void);
> #define EFI_RNG_ALGORITHM_RAW EFI_GUID(0xe43176d7, 0xb6e8, 0x4827, 0xb7, 0x84, 0x7f, 0xfd, 0xc4, 0xb6, 0x85, 0x61)
> #define EFI_MEMORY_ATTRIBUTES_TABLE_GUID EFI_GUID(0xdcfa911d, 0x26eb, 0x469f, 0xa2, 0x20, 0x38, 0xb7, 0xdc, 0x46, 0x12, 0x20)
> #define EFI_CONSOLE_OUT_DEVICE_GUID EFI_GUID(0xd3b36f2c, 0xd551, 0x11d4, 0x9a, 0x46, 0x00, 0x90, 0x27, 0x3f, 0xc1, 0x4d)
> +#define APPLE_PROPERTIES_PROTOCOL_GUID EFI_GUID(0x91bd12fe, 0xf6c3, 0x44fb, 0xa5, 0xb7, 0x51, 0x22, 0xab, 0x30, 0x3a, 0xe0)
>
> /*
> * This GUID is used to pass to the kernel proper the struct screen_info
> --
> 2.10.1
>
next prev parent reply other threads:[~2016-11-03 23:31 UTC|newest]
Thread overview: 11+ messages / expand[flat|nested] mbox.gz Atom feed top
2016-11-03 10:18 [PATCH v3 0/3] Apple device properties Lukas Wunner
[not found] ` <cover.1478145888.git.lukas-JFq808J9C/izQB+pC5nmwQ@public.gmane.org>
2016-11-03 10:18 ` [PATCH v3 1/3] efi: Add device path parser Lukas Wunner
2016-11-03 10:18 ` [PATCH v3 3/3] thunderbolt: Use Device ROM retrieved from EFI Lukas Wunner
[not found] ` <776fcc302f58628d1a122ba929751760c554cbfc.1478145888.git.lukas-JFq808J9C/izQB+pC5nmwQ@public.gmane.org>
2016-11-06 23:02 ` Andreas Noever
[not found] ` <CAMxnaaVfT+gxgq4q76Jz8gY_OfaBr_ToXQ8f-bYGwjcd2eS=9A-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org>
2016-11-07 11:28 ` Lukas Wunner
2016-11-03 10:18 ` [PATCH v3 2/3] x86/efi: Retrieve and assign Apple device properties Lukas Wunner
[not found] ` <495c463bcb78131bf04ece648719fc8b3e9bd4ba.1478145888.git.lukas-JFq808J9C/izQB+pC5nmwQ@public.gmane.org>
2016-11-03 23:31 ` Matt Fleming [this message]
[not found] ` <20161103233100.GC8845-mF/unelCI9GS6iBeEJttW/XRex20P6io@public.gmane.org>
2016-11-07 10:48 ` Lukas Wunner
2016-11-03 23:34 ` [PATCH v3 0/3] " Matt Fleming
[not found] ` <20161103233458.GD8845-mF/unelCI9GS6iBeEJttW/XRex20P6io@public.gmane.org>
2016-11-06 23:13 ` Andreas Noever
[not found] ` <CAMxnaaXF2F=v=HAefZ724bJSub3=0nVYV7KkCOrhE6TMb4OrZA-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org>
2016-11-07 9:37 ` Matt Fleming
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20161103233100.GC8845@codeblueprint.co.uk \
--to=matt-mf/unelci9gs6ibeejttw/xrex20p6io@public.gmane.org \
--cc=andreas.noever-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org \
--cc=ard.biesheuvel-QSEj5FYQhm4dnm+yROfE0A@public.gmane.org \
--cc=linux-efi-u79uwXL29TY76Z2rM5mHXA@public.gmane.org \
--cc=lukas-JFq808J9C/izQB+pC5nmwQ@public.gmane.org \
--cc=pjones-H+wXaHxf7aLQT0dZR+AlfA@public.gmane.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).