blob: 575fa75b0a2f4c5dcac0e6d99ba42d1eac562f76 [file] [log] [blame]
AKASHI Takahiro2bc27ca2020-11-17 09:27:55 +09001// SPDX-License-Identifier: GPL-2.0+
2/*
3 * EFI Capsule
4 *
5 * Copyright (c) 2018 Linaro Limited
6 * Author: AKASHI Takahiro
7 */
8
9#include <common.h>
10#include <efi_loader.h>
11#include <efi_variable.h>
12#include <fs.h>
13#include <malloc.h>
14#include <sort.h>
15
16const efi_guid_t efi_guid_capsule_report = EFI_CAPSULE_REPORT_GUID;
17
18/**
19 * get_last_capsule - get the last capsule index
20 *
21 * Retrieve the index of the capsule invoked last time from "CapsuleLast"
22 * variable.
23 *
24 * Return:
25 * * > 0 - the last capsule index invoked
26 * * 0xffff - on error, or no capsule invoked yet
27 */
28static __maybe_unused unsigned int get_last_capsule(void)
29{
30 u16 value16[11]; /* "CapsuleXXXX": non-null-terminated */
31 char value[11], *p;
32 efi_uintn_t size;
33 unsigned long index = 0xffff;
34 efi_status_t ret;
35
36 size = sizeof(value16);
37 ret = efi_get_variable_int(L"CapsuleLast", &efi_guid_capsule_report,
38 NULL, &size, value16, NULL);
39 if (ret != EFI_SUCCESS || u16_strncmp(value16, L"Capsule", 7))
40 goto err;
41
42 p = value;
43 utf16_utf8_strcpy(&p, value16);
44 strict_strtoul(&value[7], 16, &index);
45err:
46 return index;
47}
48
49/**
50 * set_capsule_result - set a result variable
51 * @capsule: Capsule
52 * @return_status: Return status
53 *
54 * Create and set a result variable, "CapsuleXXXX", for the capsule,
55 * @capsule.
56 */
57static __maybe_unused
58void set_capsule_result(int index, struct efi_capsule_header *capsule,
59 efi_status_t return_status)
60{
61 u16 variable_name16[12];
62 struct efi_capsule_result_variable_header result;
63 struct efi_time time;
64 efi_status_t ret;
65
66 efi_create_indexed_name(variable_name16, "Capsule", index);
67
68 result.variable_total_size = sizeof(result);
69 result.capsule_guid = capsule->capsule_guid;
70 ret = EFI_CALL((*efi_runtime_services.get_time)(&time, NULL));
71 if (ret == EFI_SUCCESS)
72 memcpy(&result.capsule_processed, &time, sizeof(time));
73 else
74 memset(&result.capsule_processed, 0, sizeof(time));
75 result.capsule_status = return_status;
76 ret = efi_set_variable(variable_name16, &efi_guid_capsule_report,
77 EFI_VARIABLE_NON_VOLATILE |
78 EFI_VARIABLE_BOOTSERVICE_ACCESS |
79 EFI_VARIABLE_RUNTIME_ACCESS,
80 sizeof(result), &result);
81 if (ret)
82 printf("EFI: creating %ls failed\n", variable_name16);
83}
84
85/**
86 * efi_update_capsule() - process information from operating system
87 * @capsule_header_array: Array of virtual address pointers
88 * @capsule_count: Number of pointers in capsule_header_array
89 * @scatter_gather_list: Array of physical address pointers
90 *
91 * This function implements the UpdateCapsule() runtime service.
92 *
93 * See the Unified Extensible Firmware Interface (UEFI) specification for
94 * details.
95 *
96 * Return: status code
97 */
98efi_status_t EFIAPI efi_update_capsule(
99 struct efi_capsule_header **capsule_header_array,
100 efi_uintn_t capsule_count,
101 u64 scatter_gather_list)
102{
103 struct efi_capsule_header *capsule;
104 unsigned int i;
105 efi_status_t ret;
106
107 EFI_ENTRY("%p, %lu, %llu\n", capsule_header_array, capsule_count,
108 scatter_gather_list);
109
110 if (!capsule_count) {
111 ret = EFI_INVALID_PARAMETER;
112 goto out;
113 }
114
115 ret = EFI_UNSUPPORTED;
116 for (i = 0, capsule = *capsule_header_array; i < capsule_count;
117 i++, capsule = *(++capsule_header_array)) {
118 }
119out:
120 return EFI_EXIT(ret);
121}
122
123/**
124 * efi_query_capsule_caps() - check if capsule is supported
125 * @capsule_header_array: Array of virtual pointers
126 * @capsule_count: Number of pointers in capsule_header_array
127 * @maximum_capsule_size: Maximum capsule size
128 * @reset_type: Type of reset needed for capsule update
129 *
130 * This function implements the QueryCapsuleCapabilities() runtime service.
131 *
132 * See the Unified Extensible Firmware Interface (UEFI) specification for
133 * details.
134 *
135 * Return: status code
136 */
137efi_status_t EFIAPI efi_query_capsule_caps(
138 struct efi_capsule_header **capsule_header_array,
139 efi_uintn_t capsule_count,
140 u64 *maximum_capsule_size,
141 u32 *reset_type)
142{
143 struct efi_capsule_header *capsule __attribute__((unused));
144 unsigned int i;
145 efi_status_t ret;
146
147 EFI_ENTRY("%p, %lu, %p, %p\n", capsule_header_array, capsule_count,
148 maximum_capsule_size, reset_type);
149
150 if (!maximum_capsule_size) {
151 ret = EFI_INVALID_PARAMETER;
152 goto out;
153 }
154
155 *maximum_capsule_size = U64_MAX;
156 *reset_type = EFI_RESET_COLD;
157
158 ret = EFI_SUCCESS;
159 for (i = 0, capsule = *capsule_header_array; i < capsule_count;
160 i++, capsule = *(++capsule_header_array)) {
161 /* TODO */
162 }
163out:
164 return EFI_EXIT(ret);
165}