static inline efi_status_t __open_volume64(void *__image, void **__fh) { efi_file_io_interface_t *io; efi_loaded_image_64_t *image = __image; efi_file_handle_64_t *fh; efi_guid_t fs_proto = EFI_FILE_SYSTEM_GUID; efi_status_t status; void *handle = (void *)(unsigned long)image->device_handle; unsigned long func; status = efi_call_early(handle_protocol, handle, &fs_proto, (void **)&io); if (status != EFI_SUCCESS) { efi_printk(sys_table, "Failed to handle fs_proto\n"); return status; } func = (unsigned long)io->open_volume; status = efi_early->call(func, io, &fh); if (status != EFI_SUCCESS) efi_printk(sys_table, "Failed to open volume\n"); *__fh = fh; return status; }
static efi_status_t __file_size64(void *__fh, efi_char16_t *filename_16, void **handle, u64 *file_sz) { efi_file_handle_64_t *h, *fh = __fh; efi_file_info_t *info; efi_status_t status; efi_guid_t info_guid = EFI_FILE_INFO_ID; u64 info_sz; status = efi_early->call((unsigned long)fh->open, fh, &h, filename_16, EFI_FILE_MODE_READ, (u64)0); if (status != EFI_SUCCESS) { efi_printk(sys_table, "Failed to open file: "); efi_char16_printk(sys_table, filename_16); efi_printk(sys_table, "\n"); return status; } *handle = h; info_sz = 0; status = efi_early->call((unsigned long)h->get_info, h, &info_guid, &info_sz, NULL); if (status != EFI_BUFFER_TOO_SMALL) { efi_printk(sys_table, "Failed to get file info size\n"); return status; } grow: status = efi_call_early(allocate_pool, EFI_LOADER_DATA, info_sz, (void **)&info); if (status != EFI_SUCCESS) { efi_printk(sys_table, "Failed to alloc mem for file info\n"); return status; } status = efi_early->call((unsigned long)h->get_info, h, &info_guid, &info_sz, info); if (status == EFI_BUFFER_TOO_SMALL) { efi_call_early(free_pool, info); goto grow; } *file_sz = info->file_size; efi_call_early(free_pool, info); if (status != EFI_SUCCESS) efi_printk(sys_table, "Failed to get initrd info\n"); return status; }
efi_status_t efi_file_size(efi_system_table_t *sys_table_arg, void *__fh, efi_char16_t *filename_16, void **handle, u64 *file_sz) { efi_file_handle_t *h, *fh = __fh; efi_file_info_t *info; efi_status_t status; efi_guid_t info_guid = EFI_FILE_INFO_ID; unsigned long info_sz; status = fh->open(fh, &h, filename_16, EFI_FILE_MODE_READ, (u64)0); if (status != EFI_SUCCESS) { efi_printk(sys_table_arg, "Failed to open file: "); efi_char16_printk(sys_table_arg, filename_16); efi_printk(sys_table_arg, "\n"); return status; } *handle = h; info_sz = 0; status = h->get_info(h, &info_guid, &info_sz, NULL); if (status != EFI_BUFFER_TOO_SMALL) { efi_printk(sys_table_arg, "Failed to get file info size\n"); return status; } grow: status = sys_table_arg->boottime->allocate_pool(EFI_LOADER_DATA, info_sz, (void **)&info); if (status != EFI_SUCCESS) { efi_printk(sys_table_arg, "Failed to alloc mem for file info\n"); return status; } status = h->get_info(h, &info_guid, &info_sz, info); if (status == EFI_BUFFER_TOO_SMALL) { sys_table_arg->boottime->free_pool(info); goto grow; } *file_sz = info->file_size; sys_table_arg->boottime->free_pool(info); if (status != EFI_SUCCESS) efi_printk(sys_table_arg, "Failed to get initrd info\n"); return status; }
/* * Relocate a kernel image, either compressed or uncompressed. * In the ARM64 case, all kernel images are currently * uncompressed, and as such when we relocate it we need to * allocate additional space for the BSS segment. Any low * memory that this function should avoid needs to be * unavailable in the EFI memory map, as if the preferred * address is not available the lowest available address will * be used. */ static efi_status_t efi_relocate_kernel(efi_system_table_t *sys_table_arg, unsigned long *image_addr, unsigned long image_size, unsigned long alloc_size, unsigned long preferred_addr, unsigned long alignment) { unsigned long cur_image_addr; unsigned long new_addr = 0; efi_status_t status; unsigned long nr_pages; efi_physical_addr_t efi_addr = preferred_addr; if (!image_addr || !image_size || !alloc_size) return EFI_INVALID_PARAMETER; if (alloc_size < image_size) return EFI_INVALID_PARAMETER; cur_image_addr = *image_addr; /* * The EFI firmware loader could have placed the kernel image * anywhere in memory, but the kernel has restrictions on the * max physical address it can run at. Some architectures * also have a prefered address, so first try to relocate * to the preferred address. If that fails, allocate as low * as possible while respecting the required alignment. */ nr_pages = round_up(alloc_size, EFI_PAGE_SIZE) / EFI_PAGE_SIZE; status = efi_call_early(allocate_pages, EFI_ALLOCATE_ADDRESS, EFI_LOADER_DATA, nr_pages, &efi_addr); new_addr = efi_addr; /* * If preferred address allocation failed allocate as low as * possible. */ if (status != EFI_SUCCESS) { status = efi_low_alloc(sys_table_arg, alloc_size, alignment, &new_addr); } if (status != EFI_SUCCESS) { efi_printk(sys_table_arg, "ERROR: Failed to allocate usable memory for kernel.\n"); return status; } /* * We know source/dest won't overlap since both memory ranges * have been allocated by UEFI, so we can safely use memcpy. */ memcpy((void *)new_addr, (void *)cur_image_addr, image_size); /* Return the new address of the relocated image. */ *image_addr = new_addr; return status; }
efi_status_t efi_open_volume(efi_system_table_t *sys_table_arg, void *__image, void **__fh) { efi_file_io_interface_t *io; efi_loaded_image_t *image = __image; efi_file_handle_t *fh; efi_guid_t fs_proto = EFI_FILE_SYSTEM_GUID; efi_status_t status; void *handle = (void *)(unsigned long)image->device_handle; status = sys_table_arg->boottime->handle_protocol(handle, &fs_proto, (void **)&io); if (status != EFI_SUCCESS) { efi_printk(sys_table_arg, "Failed to handle fs_proto\n"); return status; } status = io->open_volume(io, &fh); if (status != EFI_SUCCESS) efi_printk(sys_table_arg, "Failed to open volume\n"); *__fh = fh; return status; }
/* * There's no way to return an informative status from this function, * because any analysis (and printing of error messages) needs to be * done directly at the EFI function call-site. * * For example, EFI_INVALID_PARAMETER could indicate a bug or maybe we * just didn't find any PCI devices, but there's no way to tell outside * the context of the call. */ static void setup_efi_pci(struct boot_params *params) { efi_status_t status; void **pci_handle = NULL; efi_guid_t pci_proto = EFI_PCI_IO_PROTOCOL_GUID; unsigned long size = 0; status = efi_call_early(locate_handle, EFI_LOCATE_BY_PROTOCOL, &pci_proto, NULL, &size, pci_handle); if (status == EFI_BUFFER_TOO_SMALL) { status = efi_call_early(allocate_pool, EFI_LOADER_DATA, size, (void **)&pci_handle); if (status != EFI_SUCCESS) { efi_printk(sys_table, "Failed to alloc mem for pci_handle\n"); return; } status = efi_call_early(locate_handle, EFI_LOCATE_BY_PROTOCOL, &pci_proto, NULL, &size, pci_handle); } if (status != EFI_SUCCESS) goto free_handle; if (efi_early->is64) setup_efi_pci64(params, pci_handle, size); else setup_efi_pci32(params, pci_handle, size); free_handle: efi_call_early(free_pool, pci_handle); }
/* * Check the cmdline for a LILO-style file= arguments. * * We only support loading a file from the same filesystem as * the kernel image. */ static efi_status_t handle_cmdline_files(efi_system_table_t *sys_table_arg, efi_loaded_image_t *image, char *cmd_line, char *option_string, unsigned long max_addr, unsigned long *load_addr, unsigned long *load_size) { struct file_info *files; unsigned long file_addr; u64 file_size_total; efi_file_handle_t *fh; efi_status_t status; int nr_files; char *str; int i, j, k; file_addr = 0; file_size_total = 0; str = cmd_line; j = 0; /* See close_handles */ if (!load_addr || !load_size) return EFI_INVALID_PARAMETER; *load_addr = 0; *load_size = 0; if (!str || !*str) return EFI_SUCCESS; for (nr_files = 0; *str; nr_files++) { str = strstr(str, option_string); if (!str) break; str += strlen(option_string); /* Skip any leading slashes */ while (*str == '/' || *str == '\\') str++; while (*str && *str != ' ' && *str != '\n') str++; } if (!nr_files) return EFI_SUCCESS; status = efi_call_early(allocate_pool, EFI_LOADER_DATA, nr_files * sizeof(*files), (void **)&files); if (status != EFI_SUCCESS) { efi_printk(sys_table_arg, "Failed to alloc mem for file handle list\n"); goto fail; } str = cmd_line; for (i = 0; i < nr_files; i++) { struct file_info *file; efi_char16_t filename_16[256]; efi_char16_t *p; str = strstr(str, option_string); if (!str) break; str += strlen(option_string); file = &files[i]; p = filename_16; /* Skip any leading slashes */ while (*str == '/' || *str == '\\') str++; while (*str && *str != ' ' && *str != '\n') { if ((u8 *)p >= (u8 *)filename_16 + sizeof(filename_16)) break; if (*str == '/') { *p++ = '\\'; str++; } else { *p++ = *str++; } } *p = '\0'; /* Only open the volume once. */ if (!i) { status = efi_open_volume(sys_table_arg, image, (void **)&fh); if (status != EFI_SUCCESS) goto free_files; } status = efi_file_size(sys_table_arg, fh, filename_16, (void **)&file->handle, &file->size); if (status != EFI_SUCCESS) goto close_handles; file_size_total += file->size; } if (file_size_total) { unsigned long addr; /* * Multiple files need to be at consecutive addresses in memory, * so allocate enough memory for all the files. This is used * for loading multiple files. */ status = efi_high_alloc(sys_table_arg, file_size_total, 0x1000, &file_addr, max_addr); if (status != EFI_SUCCESS) { efi_printk(sys_table_arg, "Failed to alloc highmem for files\n"); goto close_handles; } /* We've run out of free low memory. */ if (file_addr > max_addr) { efi_printk(sys_table_arg, "We've run out of free low memory\n"); status = EFI_INVALID_PARAMETER; goto free_file_total; } addr = file_addr; for (j = 0; j < nr_files; j++) { unsigned long size; size = files[j].size; while (size) { unsigned long chunksize; if (size > EFI_READ_CHUNK_SIZE) chunksize = EFI_READ_CHUNK_SIZE; else chunksize = size; status = efi_file_read(fh, files[j].handle, &chunksize, (void *)addr); if (status != EFI_SUCCESS) { efi_printk(sys_table_arg, "Failed to read file\n"); goto free_file_total; } addr += chunksize; size -= chunksize; } efi_file_close(fh, files[j].handle); } } efi_call_early(free_pool, files); *load_addr = file_addr; *load_size = file_size_total; return status; free_file_total: efi_free(sys_table_arg, file_size_total, file_addr); close_handles: for (k = j; k < i; k++) efi_file_close(fh, files[k].handle); free_files: efi_call_early(free_pool, files); fail: *load_addr = 0; *load_size = 0; return status; }
static void efi_retrieve_tpm2_eventlog_1_2(efi_system_table_t *sys_table_arg) { efi_guid_t tcg2_guid = EFI_TCG2_PROTOCOL_GUID; efi_guid_t linux_eventlog_guid = LINUX_EFI_TPM_EVENT_LOG_GUID; efi_status_t status; efi_physical_addr_t log_location, log_last_entry; struct linux_efi_tpm_eventlog *log_tbl = NULL; unsigned long first_entry_addr, last_entry_addr; size_t log_size, last_entry_size; efi_bool_t truncated; void *tcg2_protocol = NULL; status = efi_call_early(locate_protocol, &tcg2_guid, NULL, &tcg2_protocol); if (status != EFI_SUCCESS) return; status = efi_call_proto(efi_tcg2_protocol, get_event_log, tcg2_protocol, EFI_TCG2_EVENT_LOG_FORMAT_TCG_1_2, &log_location, &log_last_entry, &truncated); if (status != EFI_SUCCESS) return; if (!log_location) return; first_entry_addr = (unsigned long) log_location; /* * We populate the EFI table even if the logs are empty. */ if (!log_last_entry) { log_size = 0; } else { last_entry_addr = (unsigned long) log_last_entry; /* * get_event_log only returns the address of the last entry. * We need to calculate its size to deduce the full size of * the logs. */ last_entry_size = sizeof(struct tcpa_event) + ((struct tcpa_event *) last_entry_addr)->event_size; log_size = log_last_entry - log_location + last_entry_size; } /* Allocate space for the logs and copy them. */ status = efi_call_early(allocate_pool, EFI_LOADER_DATA, sizeof(*log_tbl) + log_size, (void **) &log_tbl); if (status != EFI_SUCCESS) { efi_printk(sys_table_arg, "Unable to allocate memory for event log\n"); return; } memset(log_tbl, 0, sizeof(*log_tbl) + log_size); log_tbl->size = log_size; log_tbl->version = EFI_TCG2_EVENT_LOG_FORMAT_TCG_1_2; memcpy(log_tbl->log, (void *) first_entry_addr, log_size); status = efi_call_early(install_configuration_table, &linux_eventlog_guid, log_tbl); if (status != EFI_SUCCESS) goto err_free; return; err_free: efi_call_early(free_pool, log_tbl); }
/* * Because the x86 boot code expects to be passed a boot_params we * need to create one ourselves (usually the bootloader would create * one for us). * * The caller is responsible for filling out ->code32_start in the * returned boot_params. */ struct boot_params *make_boot_params(struct efi_config *c) { struct boot_params *boot_params; struct apm_bios_info *bi; struct setup_header *hdr; efi_loaded_image_t *image; void *options, *handle; efi_guid_t proto = LOADED_IMAGE_PROTOCOL_GUID; int options_size = 0; efi_status_t status; char *cmdline_ptr; u16 *s2; u8 *s1; int i; unsigned long ramdisk_addr; unsigned long ramdisk_size; efi_early = c; sys_table = (efi_system_table_t *)(unsigned long)efi_early->table; handle = (void *)(unsigned long)efi_early->image_handle; /* Check if we were booted by the EFI firmware */ if (sys_table->hdr.signature != EFI_SYSTEM_TABLE_SIGNATURE) return NULL; if (efi_early->is64) setup_boot_services64(efi_early); else setup_boot_services32(efi_early); status = efi_call_early(handle_protocol, handle, &proto, (void *)&image); if (status != EFI_SUCCESS) { efi_printk(sys_table, "Failed to get handle for LOADED_IMAGE_PROTOCOL\n"); return NULL; } status = efi_low_alloc(sys_table, 0x4000, 1, (unsigned long *)&boot_params); if (status != EFI_SUCCESS) { efi_printk(sys_table, "Failed to alloc lowmem for boot params\n"); return NULL; } memset(boot_params, 0x0, 0x4000); hdr = &boot_params->hdr; bi = &boot_params->apm_bios_info; /* Copy the second sector to boot_params */ memcpy(&hdr->jump, image->image_base + 512, 512); /* * Fill out some of the header fields ourselves because the * EFI firmware loader doesn't load the first sector. */ hdr->root_flags = 1; hdr->vid_mode = 0xffff; hdr->boot_flag = 0xAA55; hdr->type_of_loader = 0x21; /* Convert unicode cmdline to ascii */ cmdline_ptr = efi_convert_cmdline(sys_table, image, &options_size); if (!cmdline_ptr) goto fail; hdr->cmd_line_ptr = (unsigned long)cmdline_ptr; /* Fill in upper bits of command line address, NOP on 32 bit */ boot_params->ext_cmd_line_ptr = (u64)(unsigned long)cmdline_ptr >> 32; hdr->ramdisk_image = 0; hdr->ramdisk_size = 0; /* Clear APM BIOS info */ memset(bi, 0, sizeof(*bi)); status = efi_parse_options(cmdline_ptr); if (status != EFI_SUCCESS) goto fail2; status = handle_cmdline_files(sys_table, image, (char *)(unsigned long)hdr->cmd_line_ptr, "initrd=", hdr->initrd_addr_max, &ramdisk_addr, &ramdisk_size); if (status != EFI_SUCCESS && hdr->xloadflags & XLF_CAN_BE_LOADED_ABOVE_4G) { efi_printk(sys_table, "Trying to load files to higher address\n"); status = handle_cmdline_files(sys_table, image, (char *)(unsigned long)hdr->cmd_line_ptr, "initrd=", -1UL, &ramdisk_addr, &ramdisk_size); } if (status != EFI_SUCCESS) goto fail2; hdr->ramdisk_image = ramdisk_addr & 0xffffffff; hdr->ramdisk_size = ramdisk_size & 0xffffffff; boot_params->ext_ramdisk_image = (u64)ramdisk_addr >> 32; boot_params->ext_ramdisk_size = (u64)ramdisk_size >> 32; return boot_params; fail2: efi_free(sys_table, options_size, hdr->cmd_line_ptr); fail: efi_free(sys_table, 0x4000, (unsigned long)boot_params); return NULL; }
static efi_status_t __setup_efi_pci64(efi_pci_io_protocol_64 *pci, struct pci_setup_rom **__rom) { struct pci_setup_rom *rom; efi_status_t status; unsigned long size; uint64_t attributes; status = efi_early->call(pci->attributes, pci, EfiPciIoAttributeOperationGet, 0, &attributes); if (status != EFI_SUCCESS) return status; if (!pci->romimage || !pci->romsize) return EFI_INVALID_PARAMETER; size = pci->romsize + sizeof(*rom); status = efi_call_early(allocate_pool, EFI_LOADER_DATA, size, &rom); if (status != EFI_SUCCESS) { efi_printk(sys_table, "Failed to alloc mem for rom\n"); return status; } rom->data.type = SETUP_PCI; rom->data.len = size - sizeof(struct setup_data); rom->data.next = 0; rom->pcilen = pci->romsize; *__rom = rom; status = efi_early->call(pci->pci.read, pci, EfiPciIoWidthUint16, PCI_VENDOR_ID, 1, &(rom->vendor)); if (status != EFI_SUCCESS) { efi_printk(sys_table, "Failed to read rom->vendor\n"); goto free_struct; } status = efi_early->call(pci->pci.read, pci, EfiPciIoWidthUint16, PCI_DEVICE_ID, 1, &(rom->devid)); if (status != EFI_SUCCESS) { efi_printk(sys_table, "Failed to read rom->devid\n"); goto free_struct; } status = efi_early->call(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); return status; free_struct: efi_call_early(free_pool, rom); return status; }