/* * capsule_mutex serialises access to both capsule_pending and * efi_reset_type and stop_capsules.
*/ static DEFINE_MUTEX(capsule_mutex);
/** * efi_capsule_pending - has a capsule been passed to the firmware? * @reset_type: store the type of EFI reset if capsule is pending * * To ensure that the registered capsule is processed correctly by the * firmware we need to perform a specific type of reset. If a capsule is * pending return the reset type in @reset_type. * * This function will race with callers of efi_capsule_update(), for * example, calling this function while somebody else is in * efi_capsule_update() but hasn't reached efi_capsue_update_locked() * will miss the updates to capsule_pending and efi_reset_type after * efi_capsule_update_locked() completes. * * A non-racy use is from platform reboot code because we use * system_state to ensure no capsules can be sent to the firmware once * we're at SYSTEM_RESTART. See efi_capsule_update_locked().
*/ bool efi_capsule_pending(int *reset_type)
{ if (!capsule_pending) returnfalse;
if (reset_type)
*reset_type = efi_reset_type;
returntrue;
}
/* * Whitelist of EFI capsule flags that we support. * * We do not handle EFI_CAPSULE_INITIATE_RESET because that would * require us to prepare the kernel for reboot. Refuse to load any * capsules with that flag and any other flags that we do not know how * to handle.
*/ #define EFI_CAPSULE_SUPPORTED_FLAG_MASK \
(EFI_CAPSULE_PERSIST_ACROSS_RESET | EFI_CAPSULE_POPULATE_SYSTEM_TABLE)
/** * efi_capsule_supported - does the firmware support the capsule? * @guid: vendor guid of capsule * @flags: capsule flags * @size: size of capsule data * @reset: the reset type required for this capsule * * Check whether a capsule with @flags is supported by the firmware * and that @size doesn't exceed the maximum size for a capsule. * * No attempt is made to check @reset against the reset type required * by any pending capsules because of the races involved.
*/ int efi_capsule_supported(efi_guid_t guid, u32 flags, size_t size, int *reset)
{
efi_capsule_header_t capsule;
efi_capsule_header_t *cap_list[] = { &capsule };
efi_status_t status;
u64 max_size;
if (flags & ~EFI_CAPSULE_SUPPORTED_FLAG_MASK) return -EINVAL;
/* * Every scatter gather list (block descriptor) page must end with a * continuation pointer. The last continuation pointer of the last * page must be zero to mark the end of the chain.
*/ #define SGLIST_PER_PAGE ((PAGE_SIZE / sizeof(efi_capsule_block_desc_t)) - 1)
/* * How many scatter gather list (block descriptor) pages do we need * to map @count pages?
*/ staticinlineunsignedint sg_pages_num(unsignedint count)
{ return DIV_ROUND_UP(count, SGLIST_PER_PAGE);
}
/** * efi_capsule_update_locked - pass a single capsule to the firmware * @capsule: capsule to send to the firmware * @sg_pages: array of scatter gather (block descriptor) pages * @reset: the reset type required for @capsule * * Since this function must be called under capsule_mutex check * whether efi_reset_type will conflict with @reset, and atomically * set it and capsule_pending if a capsule was successfully sent to * the firmware. * * We also check to see if the system is about to restart, and if so, * abort. This avoids races between efi_capsule_update() and * efi_capsule_pending().
*/ staticint
efi_capsule_update_locked(efi_capsule_header_t *capsule, struct page **sg_pages, int reset)
{
efi_physical_addr_t sglist_phys;
efi_status_t status;
lockdep_assert_held(&capsule_mutex);
/* * If someone has already registered a capsule that requires a * different reset type, we're out of luck and must abort.
*/ if (efi_reset_type >= 0 && efi_reset_type != reset) {
pr_err("Conflicting capsule reset type %d (%d).\n",
reset, efi_reset_type); return -EINVAL;
}
/* * If the system is getting ready to restart it may have * called efi_capsule_pending() to make decisions (such as * whether to force an EFI reboot), and we're racing against * that call. Abort in that case.
*/ if (unlikely(stop_capsules)) {
pr_warn("Capsule update raced with reboot, aborting.\n"); return -EINVAL;
}
sglist_phys = page_to_phys(sg_pages[0]);
status = efi.update_capsule(&capsule, 1, sglist_phys); if (status == EFI_SUCCESS) {
capsule_pending = true;
efi_reset_type = reset;
}
return efi_status_to_err(status);
}
/** * efi_capsule_update - send a capsule to the firmware * @capsule: capsule to send to firmware * @pages: an array of capsule data pages * * Build a scatter gather list with EFI capsule block descriptors to * map the capsule described by @capsule with its data in @pages and * send it to the firmware via the UpdateCapsule() runtime service. * * @capsule must be a virtual mapping of the complete capsule update in the * kernel address space, as the capsule can be consumed immediately. * A capsule_header_t that describes the entire contents of the capsule * must be at the start of the first data page. * * Even though this function will validate that the firmware supports * the capsule guid, users will likely want to check that * efi_capsule_supported() returns true before calling this function * because it makes it easier to print helpful error messages. * * If the capsule is successfully submitted to the firmware, any * subsequent calls to efi_capsule_pending() will return true. @pages * must not be released or modified if this function returns * successfully. * * Callers must be prepared for this function to fail, which can * happen if we raced with system reboot or if there is already a * pending capsule that has a reset type that conflicts with the one * required by @capsule. Do NOT use efi_capsule_pending() to detect * this conflict since that would be racy. Instead, submit the capsule * to efi_capsule_update() and check the return value. * * Return 0 on success, a converted EFI status code on failure.
*/ int efi_capsule_update(efi_capsule_header_t *capsule, phys_addr_t *pages)
{
u32 imagesize = capsule->imagesize;
efi_guid_t guid = capsule->guid; unsignedint count, sg_count;
u32 flags = capsule->flags; struct page **sg_pages; int rv, reset_type; int i, j;
rv = efi_capsule_supported(guid, flags, imagesize, &reset_type); if (rv) return rv;
if (i + 1 == sg_count)
sglist[j].data = 0; else
sglist[j].data = page_to_phys(sg_pages[i + 1]);
#ifdefined(CONFIG_ARM) || defined(CONFIG_ARM64) /* * At runtime, the firmware has no way to find out where the * sglist elements are mapped, if they are mapped in the first * place. Therefore, on architectures that can only perform * cache maintenance by virtual address, the firmware is unable * to perform this maintenance, and so it is up to the OS to do * it instead.
*/
efi_capsule_flush_cache_range(sglist, PAGE_SIZE); #endif
kunmap_atomic(sglist);
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.