[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
Re: [PATCH 1/6] efi: Retrieve Apple device properties
From: |
Andrei Borzenkov |
Subject: |
Re: [PATCH 1/6] efi: Retrieve Apple device properties |
Date: |
Sat, 30 Jul 2016 22:16:55 +0300 |
User-agent: |
Mozilla/5.0 (X11; Linux x86_64; rv:45.0) Gecko/20100101 Thunderbird/45.2.0 |
27.07.2016 14:20, Lukas Wunner пишет:
> Retrieve device properties from EFI using Apple's proprietary protocol
> with GUID 91BD12FE-F6C3-44FB-A5B7-5122AB303AE0, which looks like this:
>
> typedef struct {
> unsigned long signature; /* 0x10000 */
> efi_status_t (*get) (
> IN struct apple_properties_protocol *this,
> IN struct efi_generic_dev_path *device,
> IN efi_char16_t *property_name,
> OUT void *buffer,
> IN OUT u32 *buffer_size);
> /* EFI_SUCCESS, EFI_NOT_FOUND, EFI_BUFFER_TOO_SMALL */
> efi_status_t (*set) (
> IN struct apple_properties_protocol *this,
> IN struct efi_generic_dev_path *device,
> IN efi_char16_t *property_name,
> IN void *property_value,
> IN u32 property_value_len);
> /* allocates copies of property name and value */
> /* EFI_SUCCESS, EFI_OUT_OF_RESOURCES */
> efi_status_t (*del) (
> IN struct apple_properties_protocol *this,
> IN struct efi_generic_dev_path *device,
> IN efi_char16_t *property_name);
> /* EFI_SUCCESS, EFI_NOT_FOUND */
> efi_status_t (*get_all) (
> IN struct apple_properties_protocol *this,
> OUT void *buffer,
> IN OUT u32 *buffer_size);
> /* EFI_SUCCESS, EFI_BUFFER_TOO_SMALL */
> } apple_properties_protocol;
>
> Apple's EFI driver implementing this protocol, "AAPL,PathProperties",
> is a per-device key/value store which is populated by other EFI drivers.
> On macOS, these device properties are retrieved by the bootloader
> /usr/standalone/i386/boot.efi. The extension AppleACPIPlatform.kext
> subsequently merges them into the I/O Kit registry (see ioreg(8)) where
> they can be queried by other kernel extensions and user space.
>
> These device properties contain vital information which cannot be
> obtained any other way (e.g. Thunderbolt Device ROM). EFI drivers also
> use them to communicate the current device state so that OS drivers can
> pick up where EFI drivers left (e.g. GPU mode setting).
>
> The get_all() function conveniently fills a buffer with all properties
> in marshalled form which can be passed to the kernel as a setup_data
> payload. Note that the device properties will only be available if the
> kernel is booted with the efistub. Distros should adjust their
> installers to always use the efistub on Macs. grub with the "linux"
> directive will not work unless the functionality of this commit is
> duplicated in grub. (The "linuxefi" directive should work but is not
> included upstream as of this writing.)
>
Intention was to partially merge linuxefi functionality into "linux" by
autodetecting and preferring EFI stub support. Peter, any progress on this?
> Thanks to osxreverser for this blog posting which was helpful in reverse
> engineering Apple's EFI drivers and bootloader:
> https://reverse.put.as/2016/06/25/apple-efi-firmware-passwords-and-the-scbo-myth/
>
> If someone at Apple is reading this, please note there's a memory leak
> in your implementation of the del() function as the property struct is
> freed but the name and value allocations are not.
>
> Cc: address@hidden
> Cc: address@hidden
> Cc: Matt Fleming <address@hidden>
> Cc: Andreas Noever <address@hidden>
> Tested-by: Lukas Wunner <address@hidden> [MacBookPro9,1]
> Tested-by: Pierre Moreau <address@hidden> [MacBookPro11,3]
> Signed-off-by: Lukas Wunner <address@hidden>
> ---
> arch/x86/boot/compressed/eboot.c | 55
> +++++++++++++++++++++++++++++++++++
> arch/x86/include/uapi/asm/bootparam.h | 1 +
> include/linux/efi.h | 17 +++++++++++
> 3 files changed, 73 insertions(+)
>
> diff --git a/arch/x86/boot/compressed/eboot.c
> b/arch/x86/boot/compressed/eboot.c
> index ff574da..7262ee4 100644
> --- a/arch/x86/boot/compressed/eboot.c
> +++ b/arch/x86/boot/compressed/eboot.c
> @@ -571,6 +571,55 @@ free_handle:
> 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_early->call(
> + (unsigned long)sys_table->boottime->locate_protocol,
> + &guid, NULL, &properties);
> + if (status != EFI_SUCCESS)
> + 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;
> + }
> + status = efi_early->call(efi_early->is64 ?
> + ((apple_properties_protocol_64 *)properties)->get_all :
> + ((apple_properties_protocol_32 *)properties)->get_all,
> + properties, new->data, &size);
> + if (status == EFI_BUFFER_TOO_SMALL)
> + efi_call_early(free_pool, new);
> + } while (status == EFI_BUFFER_TOO_SMALL);
> +
> + if (!size) {
> + efi_call_early(free_pool, new);
> + return;
> + }
> +
> + 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)
> {
> @@ -1098,6 +1147,7 @@ free_mem_map:
> 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;
> @@ -1128,6 +1178,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) {
> 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/include/linux/efi.h b/include/linux/efi.h
> index 7f80a75..e53b4b2 100644
> --- a/include/linux/efi.h
> +++ b/include/linux/efi.h
> @@ -432,6 +432,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 signature;
> + u32 get;
> + u32 set;
> + u32 del;
> + u32 get_all;
> +} apple_properties_protocol_32;
> +
> +typedef struct {
> + u64 signature;
> + u64 get;
> + u64 set;
> + u64 del;
> + u64 get_all;
> +} apple_properties_protocol_64;
> +
> /*
> * Types and defines for EFI ResetSystem
> */
> @@ -580,6 +596,7 @@ void efi_native_runtime_setup(void);
> #define EFI_RNG_PROTOCOL_GUID EFI_GUID(0x3152bca5,
> 0xeade, 0x433d, 0x86, 0x2e, 0xc0, 0x1c, 0xdc, 0x29, 0x1f, 0x44)
> #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
>