EFI: Stash ROMs if they're not in the PCI BAR
EFI provides support for providing PCI ROMs via means other than the ROM BAR. This support vanishes after we've exited boot services, so add support for stashing copies of the ROMs in setup_data if they're not otherwise available. Signed-off-by: Matthew Garrett <mjg@redhat.com> Signed-off-by: Bjorn Helgaas <bhelgaas@google.com> Tested-by: Seth Forshee <seth.forshee@canonical.com>
This commit is contained in:
parent
8f0d8163b5
commit
dd5fc854de
4 changed files with 202 additions and 0 deletions
|
@ -8,6 +8,7 @@
|
|||
* ----------------------------------------------------------------------- */
|
||||
|
||||
#include <linux/efi.h>
|
||||
#include <linux/pci.h>
|
||||
#include <asm/efi.h>
|
||||
#include <asm/setup.h>
|
||||
#include <asm/desc.h>
|
||||
|
@ -243,6 +244,121 @@ static void find_bits(unsigned long mask, u8 *pos, u8 *size)
|
|||
*size = len;
|
||||
}
|
||||
|
||||
static efi_status_t setup_efi_pci(struct boot_params *params)
|
||||
{
|
||||
efi_pci_io_protocol *pci;
|
||||
efi_status_t status;
|
||||
void **pci_handle;
|
||||
efi_guid_t pci_proto = EFI_PCI_IO_PROTOCOL_GUID;
|
||||
unsigned long nr_pci, size = 0;
|
||||
int i;
|
||||
struct setup_data *data;
|
||||
|
||||
data = (struct setup_data *)params->hdr.setup_data;
|
||||
|
||||
while (data && data->next)
|
||||
data = (struct setup_data *)data->next;
|
||||
|
||||
status = efi_call_phys5(sys_table->boottime->locate_handle,
|
||||
EFI_LOCATE_BY_PROTOCOL, &pci_proto,
|
||||
NULL, &size, pci_handle);
|
||||
|
||||
if (status == EFI_BUFFER_TOO_SMALL) {
|
||||
status = efi_call_phys3(sys_table->boottime->allocate_pool,
|
||||
EFI_LOADER_DATA, size, &pci_handle);
|
||||
|
||||
if (status != EFI_SUCCESS)
|
||||
return status;
|
||||
|
||||
status = efi_call_phys5(sys_table->boottime->locate_handle,
|
||||
EFI_LOCATE_BY_PROTOCOL, &pci_proto,
|
||||
NULL, &size, pci_handle);
|
||||
}
|
||||
|
||||
if (status != EFI_SUCCESS)
|
||||
goto free_handle;
|
||||
|
||||
nr_pci = size / sizeof(void *);
|
||||
for (i = 0; i < nr_pci; i++) {
|
||||
void *h = pci_handle[i];
|
||||
uint64_t attributes;
|
||||
struct pci_setup_rom *rom;
|
||||
|
||||
status = efi_call_phys3(sys_table->boottime->handle_protocol,
|
||||
h, &pci_proto, &pci);
|
||||
|
||||
if (status != EFI_SUCCESS)
|
||||
continue;
|
||||
|
||||
if (!pci)
|
||||
continue;
|
||||
|
||||
status = efi_call_phys4(pci->attributes, pci,
|
||||
EfiPciIoAttributeOperationGet, 0,
|
||||
&attributes);
|
||||
|
||||
if (status != EFI_SUCCESS)
|
||||
continue;
|
||||
|
||||
if (!attributes & EFI_PCI_IO_ATTRIBUTE_EMBEDDED_ROM)
|
||||
continue;
|
||||
|
||||
if (!pci->romimage || !pci->romsize)
|
||||
continue;
|
||||
|
||||
size = pci->romsize + sizeof(*rom);
|
||||
|
||||
status = efi_call_phys3(sys_table->boottime->allocate_pool,
|
||||
EFI_LOADER_DATA, size, &rom);
|
||||
|
||||
if (status != EFI_SUCCESS)
|
||||
continue;
|
||||
|
||||
rom->data.type = SETUP_PCI;
|
||||
rom->data.len = size - sizeof(struct setup_data);
|
||||
rom->data.next = 0;
|
||||
rom->pcilen = pci->romsize;
|
||||
|
||||
status = efi_call_phys5(pci->pci.read, pci,
|
||||
EfiPciIoWidthUint16, PCI_VENDOR_ID,
|
||||
1, &(rom->vendor));
|
||||
|
||||
if (status != EFI_SUCCESS)
|
||||
goto free_struct;
|
||||
|
||||
status = efi_call_phys5(pci->pci.read, pci,
|
||||
EfiPciIoWidthUint16, PCI_DEVICE_ID,
|
||||
1, &(rom->devid));
|
||||
|
||||
if (status != EFI_SUCCESS)
|
||||
goto free_struct;
|
||||
|
||||
status = efi_call_phys5(pci->get_location, pci,
|
||||
&(rom->segment), &(rom->bus),
|
||||
&(rom->device), &(rom->function));
|
||||
|
||||
if (status != EFI_SUCCESS)
|
||||
goto free_struct;
|
||||
|
||||
memcpy(rom->romdata, pci->romimage, pci->romsize);
|
||||
|
||||
if (data)
|
||||
data->next = (uint64_t)rom;
|
||||
else
|
||||
params->hdr.setup_data = (uint64_t)rom;
|
||||
|
||||
data = (struct setup_data *)rom;
|
||||
|
||||
continue;
|
||||
free_struct:
|
||||
efi_call_phys1(sys_table->boottime->free_pool, rom);
|
||||
}
|
||||
|
||||
free_handle:
|
||||
efi_call_phys1(sys_table->boottime->free_pool, pci_handle);
|
||||
return status;
|
||||
}
|
||||
|
||||
/*
|
||||
* See if we have Graphics Output Protocol
|
||||
*/
|
||||
|
@ -1026,6 +1142,8 @@ struct boot_params *efi_main(void *handle, efi_system_table_t *_table,
|
|||
|
||||
setup_graphics(boot_params);
|
||||
|
||||
setup_efi_pci(boot_params);
|
||||
|
||||
status = efi_call_phys3(sys_table->boottime->allocate_pool,
|
||||
EFI_LOADER_DATA, sizeof(*gdt),
|
||||
(void **)&gdt);
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue